{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "16e94387",
      "metadata": {},
      "source": [
        "# 借助cursor生成代码"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "b7b7bbeff6237c20",
      "metadata": {
        "ExecuteTime": {
          "end_time": "2025-07-11T07:06:05.692112Z",
          "start_time": "2025-07-11T07:05:59.543386Z"
        },
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "b7b7bbeff6237c20",
        "outputId": "a4d8ae68-8890-4fa3-8f4f-62da14479467"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "sys.version_info(major=3, minor=11, micro=13, releaselevel='final', serial=0)\n",
            "matplotlib 3.10.0\n",
            "numpy 2.0.2\n",
            "pandas 2.2.2\n",
            "sklearn 1.6.1\n",
            "torch 2.6.0+cu124\n",
            "cuda:0\n"
          ]
        }
      ],
      "source": [
        "import matplotlib as mpl\n",
        "import matplotlib.pyplot as plt\n",
        "%matplotlib inline\n",
        "import numpy as np\n",
        "import sklearn\n",
        "import pandas as pd\n",
        "import os\n",
        "import sys\n",
        "import time\n",
        "from tqdm.auto import tqdm\n",
        "import torch\n",
        "import torch.nn as nn\n",
        "import torch.nn.functional as F\n",
        "\n",
        "# 打印python版本和相关库版本\n",
        "print(sys.version_info)\n",
        "\n",
        "# 打印各个模块的名称和版本号\n",
        "# 这段代码遍历matplotlib、numpy、pandas、scikit-learn和PyTorch这几个库\n",
        "# 并输出它们的名称和版本信息，方便查看环境配置\n",
        "for module in mpl, np, pd, sklearn, torch:\n",
        "    print(module.__name__, module.__version__)\n",
        "\n",
        "device = torch.device(\"cuda:0\") if torch.cuda.is_available() else torch.device(\"cpu\")\n",
        "print(device)\n",
        "\n",
        "seed = 42\n",
        "torch.manual_seed(seed)\n",
        "torch.cuda.manual_seed_all(seed)\n",
        "np.random.seed(seed)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a61058c1",
      "metadata": {
        "id": "a61058c1"
      },
      "source": [
        "# MosesTokenizer预处理 subword-nmt分词"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "cfHuRRtwArkM",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "cfHuRRtwArkM",
        "outputId": "8662c775-a184-4b6e-cfc8-694421bf77fa"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Collecting sacremoses\n",
            "  Downloading sacremoses-0.1.1-py3-none-any.whl.metadata (8.3 kB)\n",
            "Collecting subword-nmt\n",
            "  Downloading subword_nmt-0.3.8-py3-none-any.whl.metadata (9.2 kB)\n",
            "Requirement already satisfied: regex in /usr/local/lib/python3.11/dist-packages (from sacremoses) (2024.11.6)\n",
            "Requirement already satisfied: click in /usr/local/lib/python3.11/dist-packages (from sacremoses) (8.2.1)\n",
            "Requirement already satisfied: joblib in /usr/local/lib/python3.11/dist-packages (from sacremoses) (1.5.1)\n",
            "Requirement already satisfied: tqdm in /usr/local/lib/python3.11/dist-packages (from sacremoses) (4.67.1)\n",
            "Collecting mock (from subword-nmt)\n",
            "  Downloading mock-5.2.0-py3-none-any.whl.metadata (3.1 kB)\n",
            "Downloading sacremoses-0.1.1-py3-none-any.whl (897 kB)\n",
            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m897.5/897.5 kB\u001b[0m \u001b[31m18.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[?25hDownloading subword_nmt-0.3.8-py3-none-any.whl (27 kB)\n",
            "Downloading mock-5.2.0-py3-none-any.whl (31 kB)\n",
            "Installing collected packages: sacremoses, mock, subword-nmt\n",
            "Successfully installed mock-5.2.0 sacremoses-0.1.1 subword-nmt-0.3.8\n"
          ]
        }
      ],
      "source": [
        "!pip install sacremoses subword-nmt # 下载依赖"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "initial_id",
      "metadata": {
        "ExecuteTime": {
          "end_time": "2025-07-11T07:30:43.221658Z",
          "start_time": "2025-07-11T07:30:27.977023Z"
        },
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "collapsed": true,
        "id": "initial_id",
        "outputId": "9e94a9bc-0f52-42a6-ba50-60b1a0a9a79d"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "[train] 源语言文本分词完成\n",
            "[train] 目标语言文本分词完成\n",
            "[val] 源语言文本分词完成\n",
            "[val] 目标语言文本分词完成\n",
            "[test] 源语言文本分词完成\n",
            "[test] 目标语言文本分词完成\n",
            "100% 20000/20000 [00:18<00:00, 1064.75it/s]\n",
            "Finished applying bpe to train files.\n",
            "Finished applying bpe to val files.\n",
            "Finished applying bpe to test files.\n"
          ]
        }
      ],
      "source": [
        "!sh data_multi30k.sh wmt16 wmt16 de en # 执行data_multi30k.sh脚本，生成数据集"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "9VdJ0NaqAl0p",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "9VdJ0NaqAl0p",
        "outputId": "a8d94e02-78b3-49c0-ec7f-617074d59da5"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "data_multi30k.py  data_multi30k.sh  sample_data  wmt16\n"
          ]
        }
      ],
      "source": [
        "!ls"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "1acf1f44",
      "metadata": {
        "ExecuteTime": {
          "end_time": "2025-07-11T08:03:52.736243Z",
          "start_time": "2025-07-11T08:03:52.535567Z"
        },
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 702
        },
        "id": "1acf1f44",
        "outputId": "5dc24a6c-d540-4e44-e648-125b0a2b8cab"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Total sentences: 29000\n",
            "Min length: 2\n",
            "Max length: 47\n",
            "Mean length: 13.03\n",
            "Median length: 12.0\n"
          ]
        },
        {
          "data": {
            "image/png": "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uv322/Xoo49qyZIluuuuu2pts3XrVl199dXq1KmTnnzySdntdu3cuVNr166VJLVr105PPvmkHn/8cd199926+OKLJUkXXHCBM+P333/XlVdeqZtvvlmDBw9WfHz8Cfv1z3/+UxaLRY888oiys7M1bdo09e3bV5s2bTqp2Rx3+vZHhmHommuu0cqVKzVixAh16dJFixcv1kMPPaQDBw7oxRdfdGm/Zs0affjhh7rvvvsUERGhl156SYMGDVJ6enqNIvePiouL1bt3b+3cuVOjRo1SSkqK5s+fr2HDhik3N1cPPPCA2rVrp7feektjxoxR06ZNNW7cOElSbGxsrZnJycmSpHfeeUcXXnjhCWcis7Ky1KNHD2ehFBsbqy+++EIjRoxQfn5+jZu1Pfvss7JarXrwwQeVl5enyZMn67bbbtM333wjSXrssceUl5en/fv3O/dReHi4pKpTc6+55hqtWbNGd999t9q1a6fNmzfrxRdf1K+//qqPP/74pPfpwYMHdf755ys3N1d333232rZtqwMHDuiDDz7Q0aNHZbPZdPToUfXq1UsHDhzQPffco2bNmunrr7/W+PHjlZGR4ZXrz9966y0NHTpUqampeu6553T06FG9/PLLuuiii7Rx40aXf3iorKxUamqqunfvrhdeeEHLli3TlClT1LJlS40cOdK5rwYMGKBvv/1WI0eOVNu2bfXJJ59o6NChLtu95557dPDgQS1dulRvvfVWrX2bO3euCgoKdM8998hisWjy5Mm67rrrtHv3bucZHoMGDdLWrVt1//33q3nz5srOztbSpUuVnp7u0enGnv4+uOuGG25Q69at9cwzzzj/EWzp0qXavXu3hg8froSEBG3dulWvvPKKtm7dqvXr1//pqeQ7d+7U9ddfrxEjRmjo0KF6/fXXNWzYMHXr1k0dOnQ44WePHDmiK664Qtddd51uvPFGffDBB3rkkUfUsWNHXXnllZKq/hHvsssuU0ZGhh544AElJCRo7ty5Wrlypen9IdV+DHdnn1x33XX69ddf9e677+rFF19Uo0aNJP3v+PLyyy+rQ4cOuuaaaxQYGKgFCxbovvvuk8PhUFpamlf6DuA0ZwAADMMwjNmzZxuSjO++++64baKiooxzzjnH+f6JJ54w/ngoffHFFw1JRk5OznEzvvvuO0OSMXv27BrrevXqZUgyZs2aVeu6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9TXcoaGhddwT1BfVY8nM/QEougEAAADUK5xSDm/xxlii6Abg91rEtNAnN3+iFjEtTAa1kD75pOoVAAAAOAW4phuA34sOjtY1ba7xQlC0dI0XcgAAAAA3MdMNwO9lFmZq0leTlFmYaTIoU5o0qeoVAADATwwbNkwWi0X33ntvjXVpaWmyWCwaNmzYqe+YGz788EP169dPDRs2lMVi0aZNm2q0ueeee9SyZUuFhIQoNjZWAwcO1C+//HLCXMMw9PjjjysxMVEhISHq27evduzY4dLmmmuuUbNmzRQcHKzExETdfvvtOnjwoDe/nldQdAPwewcLDurRFY/qYIHJg+jBg9Kjj1a9AgAA+JGkpCS99957Ki4udi4rKSnR3Llz1axZszrs2YkVFRXpoosu0nPPPXfcNt26ddPs2bP1888/a/HixTIMQ/369VNlZeVxPzN58mS99NJLmjVrlr755huFhYUpNTVVJX949Oull16qefPmafv27frvf/+rXbt26frrr/fq9/MGim4AAAAAqGNdu3ZVUlKSPvzwQ+eyDz/8UM2aNdM555zj0tbhcGjSpElKSUlRSEiIOnfurA8++MC5vrKyUiNGjHCub9OmjaZPn+6SMWzYMF177bV64YUXlJiYqIYNGyotLe2k79J9++236/HHH1ffvn2P2+buu+/WJZdcoubNm6tr1656+umntW/fPv3222+1tjcMQ9OmTdPf//53DRw4UJ06ddKbb76pgwcP6uOPP3a2GzNmjHr06KHk5GRdcMEF+tvf/qb169ebutO4L1B0AwAAAIAfuOOOOzR79mzn+9dff13Dhw+v0W7SpEl68803NWvWLG3dulVjxozR4MGDtXr1aklVRXnTpk01f/58bdu2TY8//rgeffRRzZs3zyVn5cqV2rVrl1auXKk33nhDc+bM0Zw5c5zrJ0yYoObNm3v1OxYVFWn27NlKSUlRUlJSrW327NmjzMxMl0I+KipK3bt317p162r9zOHDh/XOO+/oggsuUFBQkFf7bBY3UgMAAABQv2VkVP35o5gYKSVFKimRtm2r+ZmuXatet2+Xiopc1zVvLjVoIOXkSPv2ua6LiJBat/aom4MHD9b48eO1d+9eSdLatWv13nvvadWqVc42paWleuaZZ7Rs2TL17NlTktSiRQutWbNG//nPf9SrVy8FBQVp4sSJzs+kpKRo3bp1mjdvnm688cY/7IIYzZgxQwEBAWrbtq369++v5cuX66677pIkNWrUSC1btvTouxzr3//+tx5++GEVFRWpTZs2Wrp0qWw2W61tM////Xfi4+NdlsfHxzvXVXvkkUc0Y8YMHT16VD169NDChQu90l9vougG4Peig6N1ffvrFR0cbTIoWrr++qpXAABw5vjPf6Q/FKGSpNtuk95+W9q/X+rWreZnDKPqddgwaf1613VvvSUNHizNmyeNGuW6rl8/afFij7oZGxur/v37a86cOTIMQ/3791ejRo1c2uzcuVNHjx7V5Zdf7rK8rKzM5TT0mTNn6vXXX1d6erqKi4tVVlamLl26uHymQ4cOCggIcL5PTEzU5s2bne9HjRqlUcd+Pw/ddtttuvzyy5WRkaEXXnhBN954o9auXavg4GBTuQ899JBGjBihvXv3auLEiRoyZIgWLlzoV89qp+gG4PdaxLTQ/BvmeyGohTTfCzkAAOD0cs89NR8bGhNT9dq0qbRhw/E/O2dO7TPdknTjjdL/n212iogw01PdcccdzkJ35syZNdYXFhZKkj777DM1adLEZZ3dbpckvffee3rwwQc1ZcoU9ezZUxEREXr++ef1zTffuLQ/9jRsi8Uih8Nhqv/HExUVpaioKLVu3Vo9evRQTEyMPvroI91yyy012iYkJEiSsrKylJiY6FyelZVV4x8OGjVqpEaNGumss85Su3btlJSUpPXr1zvPAvAHFN0A/F5ZZZmyi7IVFxYnW0DtpyG5F1QmZWdLcXHScU5nAgAA9VBiYtWf2gQH/+9U8tq0aXP8dbGxVX+86IorrlBZWZksFotSU1NrrG/fvr3sdrvS09PVq1evWjPWrl2rCy64QPfdd59z2a5du7zaTzMMw5BhGCotLa11fUpKihISErR8+XJnkZ2fn69vvvlGI0eOPG5u9T8YHC+3rnAjNQB+b0v2FiW9mKQt2VtMBm2RkpKqXgEAAPxQQECAfv75Z23bts3l1O9qERERevDBBzVmzBi98cYb2rVrl3744Qf961//0htvvCFJat26tb7//nstXrxYv/76q/7xj3/ou+++O+m+zJgxQ3369Dlhm8OHD2vTpk3a9v+vi9++fbs2bdrkvPZ69+7dmjRpkjZs2KD09HR9/fXXuuGGGxQSEqKrrrrKmdO2bVt99NFHkqpm3EePHq2nn35an376qTZv3qwhQ4aocePGuvbaayVJ33zzjWbMmKFNmzZp7969WrFihW655Ra1bNnSr2a5JWa6AQAAAMCvREZGnnD9U089pdjYWE2aNEm7d+9WdHS0unbtqkcffVSSdM8992jjxo266aabZLFYdMstt+i+++7TF198cVL9OHTo0J/OkH/66acud1i/+eabJUlPPPGEJkyYoODgYH311VeaNm2ajhw5ovj4eF1yySX6+uuvFRcX5/zc9u3blZeX53xffdO1u+++W7m5ubrooou0aNEi5zXgoaGh+vDDD/XEE0+oqKhIiYmJuuKKK/T3v//deZq9v7AYRvUdAnA8+fn5ioqKUl5envMXwOFwKDs7W3FxcbJaOWEA9Yc3x/aAAeb7s2CB9EPGD+r2SjdtuHuDuiae4PSvP/PDD1U3Stmw4cSnkaFe4riN+oqxjfrKk7FdUlKiPXv2KCUlxfQNugDpxGOqtjqxNhyZAQAAAADwEYpuAAAAAAB8hGu6Afi9LgldVPJYiYICgv688QmDukglJVKQyRwAAADATRTdAPye1WKVPdALN8SwWiU/u7EGAAAA6jdOLwfg9379/Vf1ntNbv/7+q8mgX6XevateAQAAgFOAohuA3yssK9TqvatVWFZoMqhQWr266hUAAAA4BSi6AQAAAADwEYpuAAAAAAB8hKIbAAAAAAAfoegG4PeaRTXT/w34PzWLamYyqJn0f/9X9QoAAHAGWbVqlSwWi3JzcyVJc+bMUXR0dJ326UxB0Q3A7zUKbaQ7u96pRqGNTAY1ku68s+oVAADATwwbNkwWi0X33ntvjXVpaWmyWCwaNmyYV7d500036dc6eqLLP//5T11wwQUKDQ2ttfD/8ccfdcsttygpKUkhISFq166dpk+f/qe5hw8f1m233abIyEhFR0drxIgRKjzmBro//fSTLr74YgUHByspKUmTJ0/21tc6LopuAH7v0NFDevWHV3Xo6CGTQYekV1+tegUAAPAjSUlJeu+991RcXOxcVlJSorlz56qZD87SCwkJUVxcnNdz3VFWVqYbbrhBI0eOrHX9hg0bFBcXp7fffltbt27VY489pvHjx2vGjBknzL3tttu0detWLV26VAsXLtSXX36pu+++27k+Pz9f/fr1U3JysjZs2KDnn39eEyZM0CuvvOLV73csim4Afi89L113LbhL6XnpJoPSpbvuqnoFAADwI127dlVSUpI+/PBD57IPP/xQzZo10znnnOPS1uFwaNKkSUpJSVFISIg6d+6sDz74wKXN559/rrPOOkshISG69NJL9dtvv7msP/b08l27dmngwIGKj49XeHi4zjvvPC1btszlM82bN9czzzyjO+64QxEREWrWrJlHBevEiRM1ZswYdezYsdb1d9xxh6ZPn65evXqpRYsWGjx4sIYPH+6yb471888/a9GiRXr11VfVvXt3XXTRRfrXv/6l9957TwcPHpQkvfPOOyorK9Prr7+uDh066Oabb9Zf//pXTZ069aS/w8mo06L75ZdfVqdOnRQZGanIyEj17NlTX3zxhXN9SUmJ0tLS1LBhQ4WHh2vQoEHKyspyyUhPT1f//v0VGhqquLg4PfTQQ6qoqHBps2rVKnXt2lV2u12tWrXSnDlzTsXXAwAAAAC33XHHHZo9e7bz/euvv67hw4fXaDdp0iS9+eabmjVrlrZu3aoxY8Zo8ODBWr16tSRp3759uu666zRgwABt2rRJd955p/72t7+dcNuFhYW66qqrtHz5cm3cuFFXXHGFBgwYoPRjJiumTJmic889Vxs3btR9992nkSNHavv27c71vXv39vqp8JKUl5enBg0aHHf9unXrFB0drXPPPde5rG/fvrJarfrmm2+cbS655BLZbDZnm9TUVG3fvl1Hjhzxep+rBfos2Q1NmzbVs88+q9atW8swDL3xxhsaOHCgNm7cqA4dOmjMmDH67LPPNH/+fEVFRWnUqFG67rrrtHbtWklSZWWl+vfvr4SEBH399dfKyMjQkCFDFBQUpGeeeUaStGfPHvXv31/33nuv3nnnHS1fvlx33nmnEhMTlZqaWpdfHwAAAMApkFGQoYzCDJdlMcExSolJUUlFibblbKvxma6JXSVJ2w9tV1F5kcu65tHN1SCkgXKKcrQvf5/LughbhFo3bO1RPwcPHqzx48dr7969kqS1a9fqvffe06pVq5xtSktL9cwzz2jZsmXq2bOnJKlFixZas2aN/vOf/6hXr156+eWX1bJlS02ZMkWS1KZNG23evFnPPffccbfduXNnde7c2fn+qaee0kcffaRPP/1Uo0aNci6/6qqrdN9990mSHnnkEb344otauXKl2rRpI0lq1qyZEhMTPfr+x/P111/r/fff12effXbcNpmZmTVOlw8MDFSD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FKDoBgAAAADARyi6AQAAAADwEYpuAAAAAAB8hKIbAAAAAAAf4ZFhAPxe1NGuuvp7w3xQ166S4YUcAAAAwE3MdAMAAAAA4CMU3QD8XqF9u9a07alC+3ZzQdu3Sz17Vr0CAAAApwBFNwC/VxlQpNzw9aoMKDIXVFQkrV9f9QoAAACcAhTdAAAAAAD4CDdSA1CvDRjwv/9umSdNkzR6tLQryv2MBQu83CkAAACcMZjpBgAAAADAR+q06J40aZLOO+88RUREKC4uTtdee622H3ODo969e8tisbj8uffee13apKenq3///goNDVVcXJweeughVVRUuLRZtWqVunbtKrvdrlatWmnOnDm+/noAvCSktLm67H5LIaXNTeVkhTTXlC5vKSvEXA4AAADgrjotulevXq20tDStX79eS5cuVXl5ufr166eiY25ydNdddykjI8P5Z/Lkyc51lZWV6t+/v8rKyvT111/rjTfe0Jw5c/T444872+zZs0f9+/fXpZdeqk2bNmn06NG68847tXjx4lP2XQF4zlbZQE0PD5atsoGpnEJbA61qOliFNnM5AAAAgLvq9JruRYsWubyfM2eO4uLitGHDBl1yySXO5aGhoUpISKg1Y8mSJdq2bZuWLVum+Ph4denSRU899ZQeeeQRTZgwQTabTbNmzVJKSoqmTJkiSWrXrp3WrFmjF198Uampqb77ggC8ojQwRxkx85R45EbZK2I9zokszdFFGfO0JvFG5ds9zwEAAADc5Vc3UsvLy5MkNWjgOgv1zjvv6O2331ZCQoIGDBigf/zjHwoNDZUkrVu3Th07dlR8fLyzfWpqqkaOHKmtW7fqnHPO0bp169S3b1+XzNTUVI0ePbrWfpSWlqq0tNT5Pj8/X5LkcDjkcDic/20YhvM94G8sFk8/55DFYshiccjs8Pa0D8cqse3VluRRiinqruDKhh7nxJbs1cgto7Q9prsKgt3P4de8fuC4jfqKsY36irENf+fu2PSbotvhcGj06NG68MILdfbZZzuX33rrrUpOTlbjxo31008/6ZFHHtH27dv14YcfSpIyMzNdCm5JzveZmZknbJOfn6/i4mKFhIS4rJs0aZImTpxYo485OTkqKSlx9jcvL0+GYchq5X508D9JSZ5+0qFGjarGdna2ubHteR9cBQceliQlJBxWbEW2xzkJwf/LKY91Pyfb803C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u9XOo6J78uTJ6tOnj77//nuVlZXp4Ycf1tatW3X48GGtXbvWk0i37N+/X7///rsSExMlST179lRubq42bNigbt26SZJWrFghh8Oh7t27O9s89thjKi8vV1BQkCRp6dKlatOmTa2nlktVN2+rbcbearW6/MJbLJYaywBJOskb+fsdw7DIMMyPbe/tB6vz1TD12DBv5Zx+OExV4biN+oqxjfqKsQ1/5u649Gj0nn322fr111910UUXaeDAgSoqKtJ1112njRs3qmXLlm7nFBYWatOmTdq0aZMkac+ePdq0aZPS09NVWFiohx56SOvXr9dvv/2m5cuXa+DAgWrVqpVSU1MlSe3atdMVV1yhu+66S99++63Wrl2rUaNG6eabb1bjxo0lSbfeeqtsNptGjBihrVu36v3339f06dNdZrIB+LfQ0hY6d8cnCi1tYSonM7SFnjr3E2WGmssBAAAA3HXSM93l5eW64oorNGvWLD322GOmNv7999+7nI5eXQgPHTpUL7/8sn766Se98cYbys3NVePGjdWvXz899dRTLrPQ77zzjkaNGqU+ffrIarVq0KBBeumll5zro6KitGTJEqWlpalbt25q1KiRHn/8cR4XBpxGgiqjlZB3jemcoqBofZtgPgcAAABw10kX3UFBQfrpp5+8svHevXvLOMH5p4sXL/7TjAYNGmju3LknbNOpUyd99dVXJ90/AP6hJDBT+xvNVtNDwxVcUfu9GNwRXZKpvvtna1nT4coN9jwHAAAAcJdHp5cPHjxYr732mrf7AgC1KrUd1C9NH1Wp7aCpnIalBzX0l0fVsNRcDgAAAOAuj26kVlFRoddff13Lli1Tt27dFBYW5rJ+6tSpXukcAAAAAACns5Mqunfv3q3mzZtry5Yt6tq1qyTp119/dWljsVi81zsAAAAAAE5jJ1V0t27dWhkZGVq5cqUk6aabbtJLL72k+Ph4n3QOAAAAAIDT2Uld033sTc+++OILFRUVebVDAHCswIpoJR6+XoEV0aZyCgOjtSbxehUGmssBAAAA3OXRNd3VTnTncQDwlrCyFuq2e77pnKywFnqum/kcAAAAwF0nNdNtsVhqXLPNNdwAfM1hKVNx0H45LGWmcgIdZWpYvF+BDnM5AAAAgLtOaqbbMAwNGzZMdrtdklRSUqJ77723xt3LP/zwQ+/1EMAZryBki75q300X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",
            "text/plain": [
              "<Figure size 1000x600 with 1 Axes>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "# 读取训练集源文件并分析句子长度\n",
        "with open(\"wmt16/train_src.bpe\", \"r\", encoding=\"utf8\") as file:\n",
        "    lines = file.readlines()\n",
        "\n",
        "# 分割每行并计算长度\n",
        "lengths = [len(line.strip().split()) for line in lines]\n",
        "\n",
        "# 创建句子长度的直方图\n",
        "plt.figure(figsize=(10, 6))\n",
        "plt.hist(lengths, bins=50, alpha=0.7, color='blue')\n",
        "plt.xlabel('Sentence Length (number of tokens)')\n",
        "plt.ylabel('Frequency')\n",
        "plt.title('Distribution of Sentence Lengths in Training Data')\n",
        "plt.grid(True, alpha=0.3)\n",
        "\n",
        "# 添加一些统计信息作为文本\n",
        "plt.axvline(np.mean(lengths), color='r', linestyle='dashed', linewidth=1, label=f'Mean: {np.mean(lengths):.2f}')\n",
        "plt.axvline(np.median(lengths), color='g', linestyle='dashed', linewidth=1, label=f'Median: {np.median(lengths):.2f}')\n",
        "plt.legend()\n",
        "\n",
        "# 显示一些统计信息\n",
        "print(f\"Total sentences: {len(lengths)}\")\n",
        "print(f\"Min length: {min(lengths)}\")\n",
        "print(f\"Max length: {max(lengths)}\")\n",
        "print(f\"Mean length: {np.mean(lengths):.2f}\")\n",
        "print(f\"Median length: {np.median(lengths)}\")\n",
        "\n",
        "plt.tight_layout()\n",
        "plt.show()\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "f7c22d1a",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 702
        },
        "id": "f7c22d1a",
        "outputId": "3d69a82f-5503-4d60-d5a6-f0b04b162748"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Total sentences: 29000\n",
            "Min length: 4\n",
            "Max length: 41\n",
            "Mean length: 13.25\n",
            "Median length: 13.0\n"
          ]
        },
        {
          "data": {
            "image/png": "iVBORw0KGgoAAAANSUhEUgAAA90AAAJOCAYAAACqS2TfAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAkjBJREFUeJzs3Xd8FHX+x/H3puymFyCFQIBQpClS9CA2EJAgGPXADlLEHjwB2w89FfROFKVYUM7zBD1FBc8CNooCHggqYJSidAglCaGlkb7z+4PLyJJkhc0uybKv5+ORxzqf+X5nvjPfzMon35n5WgzDMAQAAAAAANzOr64bAAAAAADA2YqkGwAAAAAADyHpBgAAAADAQ0i6AQAAAADwEJJuAAAAAAA8hKQbAAAAAAAPIekGAAAAAMBDSLoBAAAAAPAQkm4AAAAAADyEpBsAamHChAmyWCxnZF+9evVSr169zOVly5bJYrHoww8/PCP7HzFihFq0aHFG9uWqgoIC3X777YqPj5fFYtGYMWPqukmox3bt2iWLxaIXXnjBY/s4k98R7jJ79mxZLBbt2rXrtOtWfi8tW7bM7e0CAG9F0g0A/1P5D83Kn6CgICUkJCglJUUvvfSS8vPz3bKf/fv3a8KECUpPT3fL9typPrftVDzzzDOaPXu27rnnHv373//WrbfeWmPZ0tJSvfjii+rSpYsiIiIUFRWljh076s4779Rvv/3m0XbOmTNH06dP9+g+zqRevXrp3HPPretm1OiLL77QhAkT6roZtdarVy+H76iafs6GY3WFJ7/Dv/vuO02YMEFHjx51X4MB+AyLYRhGXTcCAOqD2bNna+TIkXrqqaeUlJSksrIyZWVladmyZVq8eLGaNWum+fPnq1OnTmad8vJylZeXKygo6JT3s2bNGl144YWaNWuWRowYccr1SktLJUlWq1XS8RGlyy+/XPPmzdN11113yttxtW1lZWWy2+2y2Wxu2Zcn9OjRQwEBAVqxYsUflk1NTdWXX36pm2++WcnJySorK9Nvv/2mzz77TE8//fRp9c3puuqqq7RhwwaXRhLro169eungwYPasGFDXTelWqNHj9aMGTN08j95du3apaSkJD3//PN68MEHPbJvV74jarJ48WJlZ2ebyz/++KNeeuklPfroo2rfvr0Z79Spk8P31OmqqKhQWVmZbDbbaY/S2+12lZaWymq1ys/vzI7tuPIdfqpeeOEFPfTQQ9q5c2e9v+MHQP0TUNcNAID65sorr9QFF1xgLo8fP17ffPONrrrqKl199dX69ddfFRwcLEkKCAhQQIBnv0qPHTumkJAQM9muK4GBgXW6/1Nx4MABdejQ4Q/L/fjjj/rss8/097//XY8++qjDuldeeYXRLLiNO78jrrjiCofloKAgvfTSS7riiiscHj05WWFhoUJDQ095P/7+/vL393epjX5+fm75A0NtnM53OACcCdxeDgCnoHfv3nr88ce1e/duvfPOO2a8uuc1Fy9erEsuuURRUVEKCwtT27ZtzcRu2bJluvDCCyVJI0eONG+DnD17tqTfb9Ndu3atLrvsMoWEhJh1T36mu1JFRYUeffRRxcfHKzQ0VFdffbX27NnjUKZFixbVjtyeuM0/alt1z3QXFhbqgQceUGJiomw2m9q2basXXnihyoiixWLR6NGj9cknn+jcc8+VzWZTx44d9dVXX1V/wk9y4MABjRo1SnFxcQoKCtL555+vt956y1xf+Rzpzp079fnnn5ttr2kkefv27ZKkiy++uMo6f39/NWzY0CG2b98+3XbbbYqLizPb/uabbzqUqWzD3Llz9fe//11NmzZVUFCQ+vTpo23btpnlevXqpc8//1y7d+8223nieS0pKdGTTz6p1q1by2azKTExUQ8//LBKSkpcPqf79u3TqFGjlJCQIJvNpqSkJN1zzz3m3ROSdPToUY0ZM8bsy9atW+u5556T3W6v9hy64ssvv9Sll16q0NBQhYeHa+DAgdq4caNDmREjRigsLEz79u3Ttddeq7CwMMXExOjBBx9URUWFQ9lDhw7p1ltvNR8PGD58uH7++ecqv7czZswwz1nlz8lef/11tWrVSjabTRdeeKF+/PFHh/VZWVkaOXKkmjZtKpvNpsaNG+uaa675w7sVqvuOqO31cCr727Rpk2655RZFR0frkksukST98ssvGjFihFq2bKmgoCDFx8frtttu06FDhxy2Ud0z3S1atNBVV12lFStW6E9/+pOCgoLUsmVLvf322w51q3umu/J7bdOmTbr88ssVEhKiJk2aaPLkyVXav3v3bl199dUKDQ1VbGysxo4dq4ULF9b6OfGavsNP5ZxMmDBBDz30kCQpKSmpyvfLrFmz1Lt3b8XGxspms6lDhw567bXXXG4rgLMPI90AcIpuvfVWPfroo1q0aJHuuOOOasts3LhRV111lTp16qSnnnpKNptN27Zt08qVKyVJ7du311NPPaUnnnhCd955py699FJJ0kUXXWRu49ChQ7ryyit10003aejQoYqLi3Parr///e+yWCx65JFHdODAAU2fPl19+/ZVenr6aY3mnErbTmQYhq6++motXbpUo0aNUufOnbVw4UI99NBD2rdvn6ZNm+ZQfsWKFfroo4907733Kjw8XC+99JIGDx6sjIyMKknuiYqKitSrVy9t27ZNo0ePVlJSkubNm6cRI0bo6NGjuv/++9W+fXv9+9//1tixY9W0aVM98MADkqSYmJhqt9m8eXNJ0rvvvquLL77Y6Uhkdna2evToYSZKMTEx+vLLLzVq1Cjl5eVVeVnbs88+Kz8/Pz344IPKzc3V5MmTNWTIEH3//feSpMcee0y5ubnau3eveY7CwsIkHb819+qrr9aKFSt05513qn379lq/fr2mTZumLVu26JNPPjntc7p//3796U9/0tGjR3XnnXeqXbt22rdvnz788EMdO3ZMVqtVx44dU8+ePbVv3z7dddddatasmb777juNHz9emZmZbnn+/N///reGDx+ulJQUPffcczp27Jhee+01XXLJJfrpp58c/vBQUVGhlJQUde/eXS+88IKWLFmiKVOmqFWrVrrnnnvMc5WamqoffvhB99xzj9q1a6dPP/1Uw4cPd9jvXXfdpf3792vx4sX697//XW3b5syZo/z8fN11112yWCyaPHmyBg0apB07dph3eAwePFgbN27UfffdpxYtWujAgQNavHixMjIyXLrd2NXr4VRdf/31atOmjZ555hnzj2CLFy/Wjh07NHLkSMXHx2vjxo16/fXXtXHjRq1evfoPbyXftm2brrvuOo0aNUrDhw/Xm2++qREjRqhbt27q2LGj07pHjhxR//79NWjQIN1www368MMP9cgjj+i8887TlVdeKen4H/F69+6tzMxM3X///YqPj9ecOXO0dOnSWp8Pqfrv8FM5J4MGDdKWLVv03nvvadq0aWrUqJGk379fXnvtNXXs2FFXX321AgICtGDBAt17772y2+1KS0tzS9sBeDkDAGAYhmHMmjXLkGT8+OOPNZaJjIw0unTpYi4/+eSTxolfpdOmTTMkGTk5OTVu48cffzQkGbNmzaqyrmfPnoYkY+bMmdWu69mzp7m8dOlSQ5LRpEkTIy8vz4zPnTvXkGS8+OKLZqx58+bG8OHD/3Cbzto2fPhwo3nz5ubyJ598Ykgy/va3vzmUu+666wyLxWJs27bNjEkyrFarQ+znn382JBkvv/xylX2daPr06YYk45133jFjpaWlRnJyshEWFuZw7M2bNzcGDhzodHuGYRh2u90813FxccbNN99szJgxw9i9e3eVsqNGjTIaN25sHDx40CF+0003GZGRkcaxY8cMw/i9P9q3b2+UlJSY5V588UVDkrF+/XozNnDgQIdzWenf//634efnZ/z3v/91iM+cOdOQZKxcudKMneo5HTZsmOHn51ft77XdbjcMwzCefvppIzQ01NiyZYvD+v/7v/8z/P39jYyMjCp1T9SzZ0+jY8eONa7Pz883oqKijDvuuMMhnpWVZURGRjrEhw8fbkgynnrqKYeyXbp0Mbp162Yu/+c//zEkGdOnTzdjFRUVRu/evav8DqelpRnV/ZNn586dhiSjYcOGxuHDh834p59+akgyFixYYBiGYRw5csSQZDz//PNOz0N1Tv6OMIzaXQ8nmjdvniHJWLp0aZX93XzzzVXKV/6unui9994zJBnffvutGav8Lty5c6cZa968eZVyBw4cMGw2m/HAAw+Yscrr4MQ2VV5rb7/9thkrKSkx4uPjjcGDB5uxKVOmGJKMTz75xIwVFRUZ7dq1q7LN6rjyHX6q5+T555+vck6cbSMlJcVo2bKl0/YC8B3cXg4ApyEsLMzpG3CjoqIkSZ9++qnLt+XabDaNHDnylMsPGzZM4eHh5vJ1112nxo0b64svvnBp/6fqiy++kL+/v/7yl784xB944AEZhqEvv/zSId63b1+1atXKXO7UqZMiIiK0Y8eOP9xPfHy8br75ZjMWGBiov/zlLyooKNDy5ctPu+0Wi0ULFy7U3/72N0VHR+u9995TWlqamjdvrhtvvNF8ptswDP3nP/9RamqqDMPQwYMHzZ+UlBTl5uZq3bp1DtseOXKkw/P3lXcM/NFxStK8efPUvn17tWvXzmFfvXv3lqQqI35/dE7tdrs++eQTpaamOjzjeuJ5qNzvpZdequjoaIf99u3bVxUVFfr222//sO3OLF68WEePHtXNN9/ssH1/f39179692pHMu+++22H50ksvdTiHX331lQIDAx3uOvHz83NpZPHGG29UdHS0w76k3/ssODhYVqtVy5Yt05EjR057+9Vx9Xo4VSefP0kOd74UFxfr4MGD6tGjhyRV+T2uTocOHcxzIx0f6W3btu0ptTksLExDhw41l61Wq/70pz9V6dMmTZro6quvNmNBQUE13lnkipO/w2t7Tk7eRm5urg4ePKiePXtqx44dys3NdVPLAXgzbi8HgNNQUFCg2NjYGtffeOONeuONN3T77bfr//7v/9SnTx8NGjRI11133Sm/ybdJkyan9dK0Nm3aOCxbLBa1bt3a42/G3r17txISEhwSfknmW5R3797tEG/WrFmVbURHR/9hErN79261adOmyvmraT+nymaz6bHHHtNjjz2mzMxMLV++XC+++KLmzp2rwMBAvfPOO8rJydHRo0f1+uuv6/XXX692OwcOHHBYPvk4K5O5U0nWtm7dql9//bXG2+L/aF+V+6vcV05OjvLy8v5wOq+tW7fql19+OeX9nq6tW7dKkvnHg5NFREQ4LAcFBVVpy8m/K7t371bjxo0VEhLiUK5169an3b4/6jObzabnnntODzzwgOLi4tSjRw9dddVVGjZsmOLj4097f9Xts3K/7krqk5KSqsQOHz6siRMn6v3336/Sp6eSHNamzU2bNq1y+3p0dLR++eUXc3n37t1q1apVlXKu9GlNTv4Or+05kaSVK1fqySef1KpVq3Ts2LEq24iMjKx9wwF4NZJuADhFe/fuVW5urtN/AAYHB+vbb7/V0qVL9fnnn+urr77SBx98oN69e2vRokWn9EZgT7xVt6ZnNSsqKlx+S/Hpqmk/Rj2YubJx48a66aabNHjwYHXs2FFz587V7NmzzbsVhg4dWuVZ4UonTz9Um+O02+0677zzNHXq1GrXJyYmum1fJ+/3iiuu0MMPP1zt+nPOOee0tlfd9qXjz3VXl6Se/Ez9mfqd/KP9nXgex4wZo9TUVH3yySdauHChHn/8cU2aNEnffPONunTp4pF91kZ13yM33HCDvvvuOz300EPq3LmzwsLCZLfb1b9//1O6M6c2ba4P13913+G1PSfbt29Xnz591K5dO02dOlWJiYmyWq364osvNG3aNLe+iBCA9yLpBoBTVPkSppSUFKfl/Pz81KdPH/Xp00dTp07VM888o8cee0xLly5V3759T3ve2z9SOYpYyTAMbdu2zSEZjI6OrnYarN27d6tly5bm8um0rXnz5lqyZIny8/MdRrt/++03c707NG/eXL/88ovsdrvDaLe79yMdv229U6dO2rp1qw4ePKiYmBiFh4eroqJCffv2ddt+ajrPrVq10s8//6w+ffq45fckJiZGERERfzh/dqtWrVRQUODWYzx5+5IUGxvrtn00b95cS5cuNafUq3Tim+Irueuaa9WqlR544AE98MAD2rp1qzp37qwpU6Y4vA27vjpy5Ii+/vprTZw4UU888YQZP/n7oy41b95cmzZtkmEYDn1WXZ+64uTv8NM5JzX9Di1YsEAlJSWaP3++w50A7nr5G4CzA890A8Ap+Oabb/T0008rKSlJQ4YMqbHc4cOHq8Q6d+4sSeaUT5Xz5bprLui3337b4RnFDz/8UJmZmeYbgaXjycLq1asdpoj67LPPqkwtdjptGzBggCoqKvTKK684xKdNmyaLxeKw/9oYMGCAsrKy9MEHH5ix8vJyvfzyywoLC1PPnj1Pe5tbt25VRkZGlfjRo0e1atUqRUdHKyYmRv7+/ho8eLD+85//VJu45uTknPa+pePnubpbV2+44Qbt27dP//znP6usKyoqUmFh4Wntx8/PT9dee60WLFigNWvWVFlfOcp4ww03aNWqVVq4cGGVMkePHlV5eflp7fdkKSkpioiI0DPPPKOysrIq6105jykpKSorK3M4V3a73Zwe7ES1veaOHTum4uJih1irVq0UHh5eZSq3+qpypPnkkWV3vJneXVJSUrRv3z7Nnz/fjBUXF1d7PZyu6r7DT+ec1PQ7VN02cnNzNWvWrFq3GcDZg5FuADjJl19+qd9++03l5eXKzs7WN998o8WLF6t58+aaP3++goKCaqz71FNP6dtvv9XAgQPVvHlzHThwQK+++qqaNm1qzpXbqlUrRUVFaebMmQoPD1doaKi6d+9e7TOYp6JBgwa65JJLNHLkSGVnZ2v69Olq3bq1w8uHbr/9dn344Yfq37+/brjhBm3fvl3vvPOOw4ucTrdtqampuvzyy/XYY49p165dOv/887Vo0SJ9+umnGjNmTJVtu+rOO+/UP/7xD40YMUJr165VixYt9OGHH2rlypWaPn16lWfKT8XPP/+sW265RVdeeaUuvfRSNWjQQPv27dNbb72l/fv3a/r06eY/pp999lktXbpU3bt31x133KEOHTro8OHDWrdunZYsWVLtH1r+SLdu3fTB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/eMf/1DPnj0VGBioiRMnmnWSkpK0atUqzZ07VzfccMMJpyBar7zyivz9/dWuXTsNHDhQX3/9te644w5JUqNGjdSqVSuXjuVkr776qh5++GEVFhaqbdu2Wrx4saxW6ynVLS4u1iOPPKKbb75ZERERZvwvf/mLunbtqgYNGui7777T+PHjlZmZqalTp7qlze5C0g3AJ0QFRem6DtcpKijqhGCUdN11xz8BAMDZ6x//kE5IQiVJQ4ZI77wj7d0rdetWtY5hHP8cMUJavdpx3b//LQ0dKs2dK40e7biuXz9p4UKXmhkTE6OBAwdq9uzZMgxDAwcOVKNGjRzKbNu2TceOHdMVV1zhEC8tLXW4DX3GjBl68803lZGRoaKiIpWWlqpz584OdTp27Ch/f39zuXHjxlq/fr25PHr0aI0++fhcNGTIEF1xxRXKzMzUCy+8oBtuuEErV65UUFCQ03plZWW64YYbZBiGXnvtNYd148aNM/+7U6dOslqtuuuuuzRp0iTZbDa3tNsdSLoB+ISW0S017/p5JwVbSvPmVV8BAACcPe66q+o0odHRxz+bNpXWrq257uzZ1Y90S9INN0j/G202hYfXpqW67bbbzER3xowZVdYXFBRIkj7//HM1adLEYV1lovn+++/rwQcf1JQpU5ScnKzw8HA9//zz+v777x3KBwYGOixbLBbZ7fZatb8mkZGRioyMVJs2bdSjRw9FR0fr448/1s0331xjncqEe/fu3frmm28cRrmr0717d5WXl2vXrl1q27atuw/BZSTdAHxCaUWpDhQeUGxorKz+/7uVqbRUOnBAio2VTvH2JgAA4IUaNz7+U52goN9vJa+Os+QtJub4jxv1799fpaWlslgsSklJqbK+Q4cOstlsysjIUM+ePavdxsqVK3XRRRfp3nvvNWPbt293aztrwzAMGYahkpKSGstUJtxbt27V0qVL1bBhwz/cbnp6uvz8/BQbG+vO5tYaL1ID4BM2HNigxGmJ2nBgwwnBDVJi4vFPAACAesDf31+//vqrNm3a5HDrd6Xw8HA9+OCDGjt2rN566y1t375d69at08svv6y33npLktSmTRutWbNGCxcu1JYtW/T444/rxx9/PO22vPLKK+rTp4/TMocPH1Z6ero2/e+5+M2bNys9PV1ZWVmSpB07dmjSpEnmm8e/++47XX/99QoODtaAAQPM7bRr104ff/yxpOMJ93XXXac1a9bo3XffVUVFhbKyspSVlaXS0lJJ0qpVqzR9+nT9/PPP2rFjh959913zhXLRlXcx1BOMdAMAAABAPfJHt1E//fTTiomJ0aRJk7Rjxw5FRUWpa9euevTRRyVJd911l3766SfdeOONslgsuvnmm3Xvvffqyy+/PK12HDx48A9HyOfPn6/bbrvNXL7pppskSU8++aQmTJigoKAg/fe//9X06dN15MgRxcXF6bLLLtN3333nMCK9efNm5ebmSpL27dun+fPnS1KV59CXLl2qXr16yWaz6f3339eECRNUUlKipKQkjR071uE57/rCYhiVbwhATfLy8hQZGanc3Nw/vADORna7XQcOHFBsbKz8/Lg5wpvUtu9SU2u3/wULalffndZlrlO317tp7Z1r1bXx/24hW7fu+ItT1q51fltZHeC68270n/ei77wXfee93Nl3xcXF2rlzp5KSkv7wBV1wD8MwVF5eroCAAFkslrpujts5+5061TyRbyQAAAAAADyEpBsAAAAAAA/hmW4APqFzfGcVP1asQP8Tpsbo3FkqLpZOmi4DAAAAcBeSbgA+wc/iJ1uA7aSgn2SzVV8BAAAAcANuLwfgE7Yc2qJes3tpy6EtJwS3SL16Hf8EAAAAPICkG4BPKCgt0PLdy1VQWnBCsEBavvz4JwAAAOABJN0AAAAAAHgISTcAAAAAAB5C0g0AAAAAgIeQdAPwCc0im+mfqf9Us8hmJwSbSf/85/FPAACAs9iyZctksVh09OhRSdLs2bMVFRVVp23yFSTdAHxCo5BGur3r7WoU0uiEYCPp9tuPfwIAANSRESNGyGKx6O67766yLi0tTRaLRSNGjHDrPm+88UZtqaMZXP7+97/roosuUkhISLWJ/6FDh9S/f38lJCTIZrMpMTFRo0ePVl5entPtHj58WEOGDFFERISioqI0atQoFZz0wtxffvlFl156qYKCgpSYmKjJkye789CqRdINwCccPHZQb6x7QwePHTwheFB6443jnwAAAHUoMTFR77//voqKisxYcXGx5syZo2YeuCsvODhYsbGxbt/uqSgtLdX111+ve+65p9r1fn5+uuaaazR//nxt2bJFs2fP1pIlS6r9o8SJhgwZoo0bN2rx4sX67LPP9O233+rOO+801+fl5alfv35q3ry51q5dq+eff14T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fvB6M9Yif73eXRyrFvnrndQEAAAAXFenSffy5cuVlpam1atXa/HixSorK1O/fv1UWFholhk7dqwWLFigefPmafny5dq/f78GDRpkrq+oqNDAgQNVWlqq7777Tm+99ZZmz56tJ554wiyzc+dODRw4UJdffrnS09M1ZswY3X777Vq4cOEZPV4AAAAAgG+p02e6v/rqK4fl2bNnKzY2VmvXrtVll12m3Nxc/etf/9KcOXPUu3dvSdKsWbPUvn17rV69Wj169NCiRYu0adMmLVmyRHFxcercubOefvppPfLII5owYYKsVqtmzpyppKQkTZkyRZLUvn17rVixQtOmTVNKSsoZP24AAAAAgG+oV8905+bmSpIaNGggSVq7dq3KysrUt29fs0y7du3UrFkzrVq1SpK0atUqnXfeeYqLizPLpKSkKC8vTxs3bjTLnLiNyjKV2wAAAAAAwBPqzdvL7Xa7xowZo4svvljnnnuuJCkrK0tWq1VRUVEOZePi4pSVlWWWOTHhrlxfuc5Zmby8PBUVFSk4ONhhXUlJiUpKSszlvLw8s412u72WR+p97Ha7DMPwyWN3lcVS+23U9nRbLJLFYpfFYshi8d6+c8d5+N+WzM/fz0d1sfrh5L7j8vMufG96L/rOe9F33ou+826+3H+nesz1JulOS0vThg0btGLFirpuiiZNmqSJEydWiefk5Ki4uLgOWlS37Ha7cnNzZRiG/Pzq1c0R9VZiYu23ceCAO9pgV6NGx/uunt3Ycsrccx6kJmqstjlbFNAoRH46vtHyJo31QNstKg8IUaJfLXfkdo59V9vzgDOL703vRd95L/rOe9F33s2X+y8/P/+UytWLpHv06NH67LPP9O2336pp06ZmPD4+XqWlpTp69KjDaHd2drbi4+PNMj/88IPD9irfbn5imZPfeJ6dna2IiIgqo9ySNH78eI0bN85czsvLU2JiomJiYhQREVG7g/VCdrtdFotFMTExPnchuWrPntpvIza29m04Plpq0d69MTIM7+w7d5wHb3Ry39X2PODM4nvTe9F33ou+8170nXfz5f4LCgo6pXJ1mnQbhqH77rtPH3/8sZYtW6akpCSH9d26dVNgYKC+/vprDR48WJK0efNmZWRkKDk5WZKUnJysv//97zpw4IBi//ev0sWLFysiIkIdOnQwy3zxxRcO2168eLG5jZPZbDbZ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ffddlZaW6s0335TValXHjh2Vnp6uqVOnknQDAAAAADzqtJLuNm3aKDMzU0uXLpUk3XjjjXrppZcUFxfnkcZJ0rJlyxQbG6vo6Gj17t1bf/vb39SwYUNJ0qpVqxQVFWUm3JLUt29f+fn56fvvv9ef//xnrVq1SpdddpmsVqtZJiUlRc8995yOHDmi6OjoKvssKSlRSUmJuZyXlydJstvtstvtnjrUestut8swDJ869tP425HH1PZ0WyySxWKXxWLIYvHevnPHefjflszP389HdbH64eS+c995cI0PXf5u4Yvfm2cL+s570Xfei77zbr7cf6d6zKeVdBuG4bD85ZdfqrCw8HQ2cVr69++vQYMGKSkpSdu3b9ejjz6qK6+8UqtWrZK/v7+ysrIUGxvrUCcgIEANGjRQVtbxFyNlZWUpKSnJoUzlHwmysrKqTbonTZqkiRMnVonn5OSouLjYXYfnNex2u3Jzc2UYhvz8XHoNgNdJTKzrFkgHDtSu/vFjsKtRo9z/Xbve2XfuOQ9ShF+FWhVfpWaxFYq0H99oRESF1rW6ShHNKpQYWcsduZ1j37nrPLiqtvv3Nb74vXm2oO+8F33nveg77+bL/Zefn39K5Vx6prvSyUm4u910003mf5933nnq1KmTWrVqpWXLlqlPnz4e2+/48eM1btw4czkvL0+JiYmKiYlRRESEx/ZbX9ntdlksFsXExPjMhbRnT123QDrp70mnbc+eytFSi/bujZFheGffueM8/G9L6qBPlScpr3KdYpXe4VM5BOuJk/vOfefBNbXdv6/xxe/NswV9573oO+9F33k3X+6/oKCgUyp3Wkl35RvET46dKS1btlSjRo20bds29enTR/Hx8Tpw0vBLeXm5Dh8+bD4HHh8fr+zsbIcylcs1PStus9mqvLBNkvz8/HzuF6mSxWLxqeP38N+TTkltT3XlMRiGRYbh57VJt7vOg91SqpKAA7KVx8rPOP64SYC9VJElB5Rri1W5n9XJVurGiX3nrvPgKh+59N3K1743zyb0nfei77wXfefdfLX/TvV4T/v28hEjRpgJaXFxse6+++4qby//6KOPTmezp2zv3r06dOiQGjduLElKTk7W0aNHtXbtWnXr1k2S9M0338hut6t79+5mmccee0xlZWUKDAyUJC1evFht27at9tZyAGen/OAN+m+Hbrp001pFHjv+Isjm+Rs0/b/dNObStdoe2bWOWwgAAICz0Wkl3cOHD3dYHjp0aK12XlBQoG3btpnLO3fuVHp6uho0aKAGDRpo4sSJGjx4sOLj47V9+3Y9/PDDat26tVJSUiRJ7du3V//+/XXHHXdo5syZKisr0+jRo3XTTTcpISFBknTLLbdo4sSJGjVqlB555BFt2LBBL774oqZNm1artgMAAAAA8EdOK+k+cb5sd1izZo0uv/xyc7nyOerhw4frtdde0y+//KK33npLR48eVUJCgvr166enn37a4dbvd999V6NHj1afPn3k5+enwYMH66WXXjLXR0ZGatGiRUpLS1O3bt3UqFEjPfHEE0wXBgAAAADwuFq9SK22evXq5fRlbAsXLvzDbTRo0EBz5sxxWqZTp07673//e9rtAwAAAACgNnzrSXcAAAAAAM6gOh3pBoAzJeJYZ125tlh+RqAZ2xHRWX++slgVfoFOagIAAACuI+kG4BMs8pO/4TgVoGHxU7l/1ekBAQAAAHfh9nIAPqHAtkXfte2lAtsWM5ZQsEXPfNdLCQVbnNQEAAAAXEfSDcAnVPgX6HD4clX4F5ix4IoCnXd4uYIrCpzUBAAAAFxH0g0AAAAAgIeQdAMAAAAA4CEk3QAAAAAAeAhJNwCfEFzaTJ12/VPBpc3MWE5wM73c6Z/KCW7mpCYAAADgOqYMA+ATrOWN1Ozg7Q6xPGsjLWp2ew01AAAAgNpjpBuATygNOKiMRm+oNOCgGYsoPah+GW8oovSgk5oAAACA60i6AfiEImuGfmlxh4qsGWYspihD9/1yh2KKMpzUBAAAAFxH0g0AAAAAgIeQdAMAAAAA4CG8SA0A8IdSU2u/jQULar8NAAAAb8NINwCf4F8Rpgb5PeVfEWbGivzDtL5BTxX5hzmpCQAAALiOkW4APiGs5BxdtHmZQ2x/2Dl69KJl1ZYHAAAA3IGRbgA+wZBdFZYSGbKbMYthV0BFiSyG3UlNAAAAwHUk3QB8Ql5Iur7sFqS8kHQz1jIvXR9/GaSWeek11gMAAABqg6QbAAAAAAAPIekGAAAAAMBDSLoBAAAAAPAQkm4AAAAAADyEKcMA+ITwonPV5+c9spXHmrHd4edqRJ89yrXFOqkJAAAAuI6kG4BP8DOsCi5r6hAr97PqUHDTGmoAAAAAtcft5QB8QqF1h9a2vF6F1h1mLK5whx5Ze73iCnc4qQkAAAC4jqQbgE8oDziqzAYfqjzgqBkLKz+qSzI/VFj50RrrAQAAALVB0g0AAAAAgIeQdAMAAAAA4CEk3QAAAAAAeAhJNwCfYCtNULu9z8hWmmDGDtkS9Fa7Z3TIluCkJgAAAOA6pgwD4BOCyuPVOmu8Q+xoULw+bD2+hhoAAABA7THSDcAnlPkfVVbkfJX5HzVjoWVH9aes+QotO1pjPQAAAKA2SLoB+IRjth1a0+YaHbP9Pid3/LEdenzNNYo/xjzdAAAA8AySbgAAAAAAPISkGwAAAAAADyHpBgAAAADAQ0i6AfgEP3uQwoo6yM8eZMZK/YKUEdZBpX5BTmoCAAAArmPKMAA+Iby4g3pt3OgQ2xPeQWm9NtZQAwAAAKg9RroBAAAAAPAQkm4APiE3OF1fdYlQbnC6GUvKTdcHX0UoKTe9xnoAAABAbZB0A/ANFrvK/fMli90M+cmukPJ8+cnupCIAAADgOpJuAAAAAAA8hKQbAAAAAAAPIekGAAAAAMBDSLoB+ISw4na6dNNahRW3M2N7w9ppzKVrtTesnZOaAAAAgOuYpxuAT/C3hyjyWFeHWIl/iLZHdq2hBgAAAFB7jHQD8AlF1gytb5amImuGGYspytDd69MUU5ThpCYAAADgOpJuAD6hNOCgdse+qtKAg2YsovSgBu5+VRGlB53UBAAAAFxH0g0AAAAAgIeQdAMAAAAA4CEk3QAAAAAAeAhJNwCfYC2LVVLWWFnLYs3YUWusPkkaq6PWWCc1AQAAANcxZRgAnxBc1lQd9051iB0Kbqp/dZxaQw0AAACg9hjpBuATyv0KdCR0lcr9CsxYUHmB2h5ZpaDyAic1AQAAANeRdAPwCYVBW7Sy/UUqDNpixpoUbtELKy9Sk8ItTmoCAAAAriPpBgAAAADAQ0i6AQAAAADwEJJuAAAAAAA8hKQbgE+wGAGyljWSxfh90oYKS4ByrY1UYWEiBwAAAHgG/9IE4BMiijqp3885DrFdEZ00tF9ODTUAAACA2iPpBgCcEamptau/YIF72gEAAHAm1ent5d9++61SU1OVkJAgi8WiTz75xGG9YRh64okn1LhxYwUHB6tv377aunWrQ5nDhw9ryJAhioiIUFRUlEaNGqWCAsc5d3/55RddeumlCgoKUmJioiZPnuzpQwNQz+QHbdQ357ZWftBGM9Ysf6P+8U1rNcvf6KQmAAAA4Lo6TboLCwt1/vnna8aMGdWunzx5sl566SXNnDlT33//vUJDQ5WSkqLi4mKzzJAhQ7Rx40YtXrxYn332mb799lvdeeed5vq8vDz169dPzZs319q1a/X8889rwoQJev311z1+fADqD7tfiY4FbZfdr8SMBdpLlHBsuwLtJU5qAgAAAK6r09vLr7zySl155ZXVrjMMQ9OnT9df//pXXXPNNZKkt99+W3Fxcfrkk09000036ddff9VXX32lH3/8URdccIEk6eWXX9aAAQP0wgsvKCEhQe+++65KS0v15ptvymq1qmPHjkpPT9fUqVMdknMAAAAAANyt3r69fOfOncrKylLfvn3NWGRkpLp3765Vq1ZJklatWqWoqCgz4Zakvn37ys/PT99//71Z5rLLLpPVajXLpKSkaPPmzTpy5MgZOhoAAAAAgC+qty9Sy8rKkiTFxcU5xOPi4sx1WVlZio2NdVgfEBCgBg0aOJRJSkqqso3KddHR0VX2XVJSopKS3283zcvLkyTZ7XbZ7fbaHJZXstvtMgzDp47dYqnrFki1Pd0Wi2Sx2GWxGLJYvLfv3HEe/rcl8/P381FdrH44ue/cdx68lzd9Bfni9+bZgr7zXvSd96LvvJsv99+pHnO9Tbrr0qRJkzRx4sQq8ZycHIfnyX2F3W5Xbm6uDMOQn1+9vTnCrRIT67oF0oEDtat//BjsatToeN/V4xtbnHLPeZDiLJGKPDpH8TGRshrHN+ofF6lXIufIPz5SidZa7sjtHPvOXefBm9X2HJxJvvi9ebag77wXfee96Dvv5sv9l5+ff0rl6m3SHR8fL0nKzs5W48aNzXh2drY6d+5sljlw0r/CysvLdfjwYbN+fHy8srOzHcpULleWOdn48eM1btw4czkvL0+JiYmKiYlRRERE7Q7MC9ntdlksFsXExPjMhbRnT123QDrpJo7TtmdP5WipRXv3xsgwvLPv3HEe/rclWdRKjt8GsdpqaaWTgvXCyX3nvvPgvWp7Ds4kX/zePFvQd96LvvNe9J138+X+CwoKOqVy9TbpTkpKUnx8vL7++mszyc7Ly9P333+ve+65R5KUnJyso0ePau3aterWrZsk6ZtvvpHdblf37t3NMo899pjKysoUGBgoSVq8eLHatm1b7a3lkmSz2WSz2arE/fz8fO4XqZLFYvGp4zeMum6BVNtTXXkMhmGRYfh5bdLtrvNQHJip3TH/UPOcuxRUdvwPedHFmeq/+x/6qvldOhLU2MlW6saJfeeu8+DNvO3rx9e+N88m9J33ou+8F33n3Xy1/071eOv0rBQUFCg9PV3p6emSjr88LT09XRkZGbJYLBozZoz+9re/af78+Vq/fr2GDRumhIQEXXvttZKk9u3bq3///rrjjjv0ww8/aOXKlRo9erRuuukmJSQkSJJuueUWWa1WjRo1Shs3btQHH3ygF1980WEkG8DZryQwU1sTJqokMNOMNSjJ1C1bJ6pBSaaTmgAAAIDr6nSke82aNbr88svN5cpEePjw4Zo9e7YefvhhFRYW6s4779TRo0d1ySWX6KuvvnIYxn/33Xc1evRo9enTR35+fho8eLBeeuklc31kZKQWLVqktLQ0devWTY0aNdITTzzBdGEAAAAAAI+r06S7V69e/3tJUPUsFoueeuopPfXUUzWWadCggebMmeN0P506ddJ///tfl9sJAAAAAIArfOumewAAAAAAziCSbgA+IbA8Wk0ODVFg+e8vUCwIjNbSJkNUEFj9SxUBAACA2qq3by8HAHcKKU1Sl53vOMSyQ5I0tcs7NdQAAAAAao+RbgA+ocJSrELbNlVYis1YYEWxGhduU2BFsZOaAAAAgOtIugH4hILgTVp6XhsVBG8yY80KNun1pW3UrGCTk5oAAACA60i6AQAAAADwEJJuAAAAAAA8hKQbAAAAAAAPIekGAAAAAMBDmDIMgE+IPNZVV60xHGLbI7sq9SqjhhoAAABA7THSDQAAAACAh5B0A/AJBbbNWtEuWQW2zWasScFmPb8iWU0KNjupCQAAALiOpBuAT6jwL9TRsNWq8C80Y0EVhWp3dLWCKgqd1AQAAABcR9INAAAAAICHkHQDAAAAAOAhJN0AAAAAAHgISTcAnxBc0kKdd/xbwSUtzFh2cAtN6fxvZQe3qLEeAAAAUBvM0w3AJ1grGqjp4aEOsQJrAy1rOrSGGgAAAEDtMdINwCeUBORoV8wMlQTkmLGIkhwN2DVDESU5TmoCAAAAriPpBuATiq17tKH5aBVb95ixmOI9umfDaMUU73FSEwAAAHAdt5cDAHxGamrt6i9Y4J52AAAA38FINwAAAAAAHkLSDQAAAACAh5B0A/AJ/hXhisntJ/+KcDN2zD9c62L66Zh/uJOaAAAAgOt4phuATwgraaPuWxc6xDLD2ujJ7gtrqAEAAADUHiPdAHyCoQqV+eXJUIUZ8zMqFFyWJz+jwklNAAAAwHUk3QB8Ql7Iz1rYNVJ5IT+bsaS8nzV3YaSS8n52UhMAAABwHUk3AAAAAAAeQtINAAAAAICHkHQDAAAAAOAhJN0AAAAAAHgIU4YB8AnhRefpivQDCqyIMmO7ws/TkCsOqDAwqsZ6AAAAQG2QdOOsk5pa1y1AfeRnBMpWHuMQq/ALVJ4tpoYaAAAAQO1xezkAn1Bo264fW1+tQtt2MxZfuF1//fFqxRdud1ITAAAAcB1JNwCfUO6fq+yoBSr3zzVjoeW56p69QKHluU5qAgAAAK4j6QYAAAAAwENIugEAAAAA8BCSbgAAAAAAPISkG4BPCCptog57piiotIkZOxTURG90mKJDQU2c1AQAAABcx5RhAHyCrTxOLbPHOcSO2uL0actxNdQAAAAAao+RbgA+odT/iPZHz1Op/xEzFlp6RBfvn6fQ0iNOagIAAACuI+kG4BOKbDu1rtUNKrLtNGPxRTv1f+tuUHzRTic1AQAAANeRdAMAAAAA4CEk3QAAAAAAeAhJNwAAAAAAHkLSDcAn+NmDFVHYRX72YDNW4hes7RFdVOIX7KQmAAAA4DqmDAPgE8KL2+uyX9c5xPaGt9eYy9bVUAMAAACoPUa6AQAAAADwEJJuAD4hN/gnfdHVptzgn8xYy9yf9NEXNrXM/clJTQAAAMB1JN0AfIPFkN2vVLIYv4dkKNBeKosMJxUBAAAA15F0AwAAAADgIbxIDQCAU5SaemrlLBYpMVHas0cyTrqRYsEC97cLAADUX4x0AwAAAADgIYx0A/AJYUXt1XPDBoWUtDRje8LaK63nBmWFtHRSEwAAAHAdSTcAn+BvBCu8uKNDrNQ/WBnhHWuoAQAAANQet5cD8AnHrLv1c/Pbdcy624zFHNut+36+XTHHdjupCQAAALiOpBuATygLOKQ9Mf9SWcAhMxZRdkj99vxLEWWHnNQEAAAAXEfSDQAAAACAh5B0AwAAAADgISTdAAAAAAB4CEk3AJ9gLYtTq8z/k7UszowdscZpXqv/0xFrnJOaAAAAgOuYMgyATwgua6L2+yY5xA4HN9Hb7SfVUAMAAACoPUa6AfiEcr98HQxfpnK/fDMWXJ6vcw8uU3B5vpOaAAAAgOvqddI9YcIEWSwWh5927dqZ64uLi5WWlqaGDRsqLCxMgwcPVnZ2tsM2MjIyNHDgQIWEhCg2NlYPPfSQysvLz/ShAKhjhUFbtbrt5SoM2mrGEgq3atLqy5VQuNVJTQAAAMB19f728o4dO2rJkiXmckDA700eO3asPv/8c82bN0+RkZEaPXq0Bg0apJUrV0qSKioqNHDgQMXHx+u7775TZmamhg0bpsDAQD3zzDNn/FgAAAAAAL6l3ifdAQEBio+PrxLPzc3Vv/71L82ZM0e9e/eWJM2aNUvt27fX6tWr1aNHDy1atEibNm3SkiVLFBcXp86dO+vpp5/WI488ogkTJshqtZ7pwwEAAAAA+JB6n3Rv3bpVCQkJCgoKUnJysiZNmqRmzZpp7dq1KisrU9++fc2y7dq1U7NmzbRq1Sr16NFDq1at0nnnnae4uN/fTJySkqJ77rlHGzduVJcuXardZ0lJiUpKSszlvLw8SZLdbpfdbvfQkdZfdrtdhmF4zbFbLHXdAveo7em2WCSLxS6LxZDF4h19Vx13nIf/bcn8/P18VBerH07uO/edB+/ljq+gM3UenF17XvJV6rO87f95+B19573oO+/my/13qsdcr5Pu7t27a/bs2Wrbtq0yMzM1ceJEXXrppdqwYYOysrJktVoVFRXlUCcuLk5ZWVmSpKysLIeEu3J95bqaTJo0SRMnTqwSz8nJUXFxcS2PyvvY7Xbl5ubKMAz5+dXr1wBIkhIT67oF7nHgQO3qHz8PdjVqdLzv6vkrHGrknvMghfjnK7SisRLi8tWw4vhGY0LydSS0sWIS8lXWsJY7cjvHvnPXefBmtT0H0pk8DzVfe+44DniOt/0/D7+j77wXfefdfLn/8vNP7WW89TrpvvLKK83/7tSpk7p3767mzZtr7ty5Cg4O9th+x48fr3HjxpnLeXl5SkxMVExMjCIiIjy23/rKbrfLYrEoJibGKy6kPXvqugXuERtbu/p79lSOtlm0d2+MDKP+91113HEe/rcl9dZeHZN0rHKdYvV9771yCNYTJ/ed+86D96rtOZDO3Hlwdu254zjgOd72/zz8jr7zXvSdd/Pl/gsKCjqlcvU66T5ZVFSUzjnnHG3btk1XXHGFSktLdfToUYfR7uzsbPMZ8Pj4eP3www8O26h8u3l1z4lXstlsstlsVeJ+fn4+94tUyWKxeM3xG0Zdt8A9anuqK8+DYVhkGH5em3S76zx4oxP7zpfPQyV3fP2cyfNQ07XnBV+jPs+b/p8HR/Sd96LvvJuv9t+pHq9XnZWCggJt375djRs3Vrdu3RQYGKivv/7aXL9582ZlZGQoOTlZkpScnKz169frwAn38i1evFgRERHq0KHDGW8/gLqTF7xeSzo1VV7wejPWPG+9Zi1pquZ5653UBAAAAFxXr0e6H3zwQaWmpqp58+bav3+/nnzySfn7++vmm29WZGSkRo0apXHjxqlBgwaKiIjQfffdp+TkZPXo0UOS1K9fP3Xo0EG33nqrJk+erKysLP31r39VWlpatSPZAM5ehqVMxdZ9MixlZizAKFOj4n0KMMqc1AQAAABcV6+T7r179+rmm2/WoUOHFBMTo0suuUSrV69WTEyMJGnatGny8/PT4MGDVVJSopSUFL366qtmfX9/f3322We65557lJycrNDQUA0fPlxPPfVUXR0SAAAAAMCH1Ouk+/3333e6PigoSDNmzNCMGTNqLNO8eXN98cUX7m4aAAAAAAB/yKue6QYAAAAAwJvU65FuAHCX0OI26rF5qUKL25ix/aFtNL7HUu0PbeOkJuBeqam1q79ggXvaAQAAzgySbgA+IcAerkb5vRxiRQHh2tCoV7XlAQAAAHfg9nIAPqEocJ9+bTJeRYH7zFiDon0a9ut4NSja56QmAAAA4DqSbgA+oTQwW9sbP6vSwGwzFl2areu3P6vo0mwnNQEAAADXkXQDAAAAAOAhJN0AAAAAAHgISTcAAAAAAB5C0g3AJwSWN1RizigFljc0Y3mBDbUocZTyAhs6qQkAAAC4jinDAPiEkNLmOn/3Gw6xnJDmevn8N2qoAQAAANQeI90AfEKFpUj5QRtVYSkyY9aKIjXL3yhrRZGTmgAAAIDrSLoB+ISC4F+1/NxzVRD8qxlLLPhVM5afq8SCX53UBAAAAFxH0g0AAAAAgIeQdAMAAAAA4CEk3QAAAAAAeAhJNwDfYFjkZ7dKhuX3kCwq87PKkMVJRQAAAMB1TBkGwCdEFnXRgHUlDrEdkV00aEBJDTUAAACA2mOkGwAAAAAADyHpBuAT8oN+1bftuyo/6PfpwZrm/6rp33ZV03ymDAMAAIBnkHQD8Al2vyLlhf4ku1+RGbPZi9Qq7yfZ7EVOagIAAACuI+kGAAAAAMBDSLoBAAAAAPAQ3l4OAICPSU2tXf0FC9zTDgAAfAEj3QB8QnBJkrpun6vgkiQzlhWcpGe7zlVWcJKTmgAAAIDrGOkG4BOsFdFKOHK9Q6zQGq2VCdfXUAMAAACoPUa6AfiEkoBs7YibqpKAbDMWVZKta3ZMVVRJtpOaAAAAgOtIugH4hGLrPm1KfEDF1n1mrGHxPt2+6QE1LN7npCYAAADgOpJuAAAAAAA8hKQbAAAAAAAPIekGAAAAAMBDSLoB+ISAikjFHU1VQEWkGSsMiNT3cakqDIh0UhMAAABwHVOGAfAJoSWtdOG2+Q6xrNBW+tuF82uoAaAmqam138aCBbXfBgAA3oCRbgA+wW4pU0lAjuyWMjPmby9TREmO/O1lTmoCAAAAriPpBuAT8oPXa3HnWOUHrzdjLfLX693FsWqRv95JTQAAAMB1JN0AAAAAAHgISTcAAAAAAB5C0g0AAAAAgIfw9nK4FW+0BQAAAIDfkXQD8AkRx85XyrpcBdhDzdjOiPN1Q0quSgJCndQEAAAAXEfSDcAnWOSvQHuEQ8xu8VdRYEQNNQDUZ9xZBQDwFjzTDcAnFNi26vs2KSqwbTVjjQu2auL3KWpcsNVJTQAAAMB1JN0AfEKFf75yIhepwj/fjIVU5KtrziKFVOQ7qQkAAAC4jqQbAAAAAAAPIekGAAAAAMBDSLoBAAAAAPAQkm4APiGoNFHn7n5FQaWJZiwnKFGvnfuKcoISndQEAAAAXMeUYQB8gq08Ri1y0hxiebYYfdEirYYaAAAAQO0x0g3AJ5T6H9beBu+o1P+wGQsrPaxee99RWOlhJzUBAAAA15F0A/AJRbZdSm95q4psu8xYXNEuPZB+q+KKdtVYDwAAAKgNkm4AAAAAADyEZ7oBAIBPSk2tGrNYpMREac8eyTCc11+wwDPtAgCcXRjpBgAAAADAQxjpBuAT/CtCFVXQQ/4VoWas2D9Uv0X1ULF/qJOaAFC96kbKTxej5QBw9iPpBuATwkra6pLfVjnE9oW11UOXrKqhBgAAAFB73F4OAAAAAICHkHQD8Am5Iev02QUW5YasM2OtctdpwWcWtcpd56QmAAAA4DqSbgAAAAAAPIRnugEAALxUbV/mxovcAMDzGOkGAAAAAMBDGOkGAADwUUx7BgCeR9INwCeEFXXQ5eu3Kqi0qRnLCOugOy/fqoNBTZ3UBAAAAFxH0g3AJ/gbQQotae0QK/MPUmZo6xpqAAAAALXnU0n3jBkz9PzzzysrK0vnn3++Xn75Zf3pT3+q62bVK9XdZmaxSImJ0p49kmGc+TYB7nDMulObmzyutvueVkhpkiQp7thODdn8uN5t+7SyQ5LquIUA4J14mRsAOOczSfcHH3ygcePGaebMmerevbumT5+ulJQUbd68WbGxsXXdPAAeVhZwRPsavquW2eOk/yXdYWVHdPm+d/Vpy3HKFkk3AHir1NTaDRKQ+APwJJ95e/nUqVN1xx13aOTIkerQoYNmzpypkJAQvfnmm3XdNAAAAADAWconRrpLS0u1du1ajR8/3oz5+fmpb9++WrVqVR22DAAAAHXNHW9xry13jLafLccBnG18Iuk+ePCgKioqFBcX5xCPi4vTb7/9VqV8SUmJSkpKzOXc3FxJ0tGjR2W32z3b2Fq6+Wb3b9NisausLE/l5VYZhudvjjh6tHb1y8vd0ow6547zcKb7zhPc9ftQXpYnFR//LC8/vtGS8jzl/e+zMlZfnNx3XBe1/12Qztx58OS1503nwZn6+jvN//POPHf9Tnv7//POlmv7yitPv47FYlfTpnnau9eqOXNq33ee+Pfwmfbee7WrfybPwYn9d+K1V9tj8AZ5eXmSJOMPnmnxiaT7dE2aNEkTJ06sEm/evHkdtMb3REfXdQvqB87Dce4+D6t0ucPyTEladXm1ZesTfh84B5XOlvNwthxHbXEeOAeVOA/HcR6OOxvOw9lwDKcqPz9fkZGRNa73iaS7UaNG8vf3V3Z2tkM8Oztb8fHxVcqPHz9e48aNM5ftdrsOHz6shg0bymKxeLy99U1eXp4SExO1Z88eRURE1HVzcBroO+9F33k3+s970Xfei77zXvSdd/Pl/jMMQ/n5+UpISHBazieSbqvVqm7duunrr7/WtddeK+l4Iv31119r9OjRVcrbbDbZbDaHWFRU1Bloaf0WERHhcxfS2YK+8170nXej/7wXfee96DvvRd95N1/tP2cj3JV8IumWpHHjxmn48OG64IIL9Kc//UnTp09XYWGhRo4cWddNAwAAAACcpXwm6b7xxhuVk5OjJ554QllZWercubO++uqrKi9XAwAAAADAXXwm6Zak0aNHV3s7OZyz2Wx68sknq9xyj/qPvvNe9J13o/+8F33nveg770XfeTf6749ZjD96vzkAAAAAAHCJ901iCAAAAACAlyDpBgAAAADAQ0i6AQAAAADwEJJu1GjChAmyWCwOP+3atavrZqEa3377rVJTU5WQkCCLxaJPPvnEYb1hGHriiSfUuHFjBQcHq2/fvtq6dWvdNBYO/qjvRowYUeU67N+/f900Fg4mTZqkCy+8UOHh4YqNjdW1116rzZs3O5QpLi5WWlqaGjZsqLCwMA0ePFjZ2dl11GJUOpW+69WrV5Vr7+67766jFqPSa6+9pk6dOpnzAScnJ+vLL78013PN1W9/1H9cd97j2WeflcVi0ZgxY8wY11/NSLrhVMeOHZWZmWn+rFixoq6bhGoUFhbq/PPP14wZM6pdP3nyZL300kuaOXOmvv/+e4WGhiolJUXFxcVnuKU42R/1nST179/f4Tp87733zmALUZPly5crLS1Nq1ev1uLFi1VWVqZ+/fqpsLDQLDN27FgtWLBA8+bN0/Lly7V//34NGjSoDlsN6dT6TpLuuOMOh2tv8uTJddRiVGratKmeffZZrV27VmvWrFHv3r11zTXXaOPGjZK45uq7P+o/ievOG/z444/6xz/+oU6dOjnEuf6cMIAaPPnkk8b5559f183AaZJkfPzxx+ay3W434uPjjeeff96MHT161LDZbMZ7771XBy1ETU7uO8MwjOHDhxvXXHNNnbQHp+fAgQOGJGP58uWGYRy/zgIDA4158+aZZX799VdDkrFq1aq6aiaqcXLfGYZh9OzZ07j//vvrrlE4ZdHR0cYbb7zBNeelKvvPMLjuvEF+fr7Rpk0bY/HixQ79xfXnHCPdcGrr1q1KSEhQy5YtNWTIEGVkZNR1k3Cadu7cqaysLPXt29eMRUZGqnv37lq1alUdtgynatmyZYqNjVXbtm11zz336NChQ3XdJFQjNzdXktSgQQNJ0tq1a1VWVuZw7bVr107NmjXj2qtnTu67Su+++64aNWqkc889V+PHj9exY8fqonmoQUVFhd5//30VFhYqOTmZa87LnNx/lbju6re0tDQNHDjQ4TqT+H/eHwmo6wag/urevbtmz56ttm3bKjMzUxMnTtSll16qDRs2KDw8vK6bh1OUlZUlSYqLi3OIx8XFmetQf/Xv31+DBg1SUlKStm/frkcffVRXXnmlVq1aJX9//7puHv7HbrdrzJgxuvjii3XuuedKOn7tWa3W/2/v7oOius4/gH8Xlrd1AUUpr/IiCl2qGEBFSEEFVHBCo2WiIglqQEwjvkBRYy2FmMygTqMSkzbp2IoxUZqoUQdUtBYIYoKgLhg1qFsQNKgBg7oBTYDz+8Px1pUXAaELv3w/MzuznHPvuc89Z8/Awz33LgYPHqyzLede/9Le2AHAvHnz4OzsDHt7e5SXl2P16tWoqKjAvn379BgtAcC5c+fg7++P+/fvQ6lU4vPPP4enpyfUajXn3ADQ0fgBnHf9XVZWFs6cOYOSkpI2dfyd1zkm3dSh8PBw6b2Xlxf8/Pzg7OyMTz/9FLGxsXqMjOjnY+7cudL7MWPGwMvLC25ubsjPz0dISIgeI6PHLVmyBF9//TWfezEAdTR28fHx0vsxY8bAzs4OISEh0Gg0cHNz+1+HSY/x8PCAWq3GnTt3sGfPHsyfPx8FBQX6Dou6qKPx8/T05Lzrx2pqarB8+XIcO3YMpqam+g5nwOHycuqywYMHw93dHVeuXNF3KNQNtra2ANDm6ZE3b96U6mjgGDFiBIYNG8Z52I8kJCQgOzsbeXl5cHR0lMptbW3x448/oqGhQWd7zr3+o6Oxa4+fnx8AcO71A8bGxhg5ciR8fX2Rnp6OsWPHIiMjg3NugOho/NrDedd/nD59Grdu3YKPjw/kcjnkcjkKCgrw7rvvQi6Xw8bGhvOvE0y6qcu0Wi00Gg3s7Oz0HQp1g6urK2xtbXH8+HGp7O7duyguLta5h4oGhmvXrqG+vp7zsB8QQiAhIQGff/45/v3vf8PV1VWn3tfXF0ZGRjpzr6KiAtXV1Zx7eva0sWuPWq0GAM69fqi1tRUPHjzgnBugHo1fezjv+o+QkBCcO3cOarVaeo0bNw7R0dHSe86/jnF5OXUoOTkZERERcHZ2xrfffovU1FQYGhoiKipK36HRE7Rarc5/gSsrK6FWq2FlZQUnJyesWLECb7/9NkaNGgVXV1ekpKTA3t4eM2fO1F/QBKDzsbOyssKbb76JyMhI2NraQqPRYNWqVRg5ciSmT5+ux6gJeLgsedeuXThw4ADMzc2le9YsLS1hZmYGS0tLxMbGIikpCVZWVrCwsMDSpUvh7++PiRMn6jn6n7enjZ1Go8GuXbswY8YMDB06FOXl5UhMTERQUFCbr8ih/601a9YgPDwcTk5OuHfvHnbt2oX8/Hzk5uZyzg0AnY0f513/Zm5urvPcCwAYNGgQhg4dKpVz/nVC349Pp/5rzpw5ws7OThgbGwsHBwcxZ84cceXKFX2HRe3Iy8sTANq85s+fL4R4+LVhKSkpwsbGRpiYmIiQkBBRUVGh36BJCNH52DU2Nopp06YJa2trYWRkJJydncWiRYvEjRs39B02CdHuuAEQ27dvl7ZpamoSr7/+uhgyZIhQKBRi1qxZora2Vn9BkxDi6WNXXV0tgoKChJWVlTAxMREjR44UK1euFHfu3NFv4CReffVV4ezsLIyNjYW1tbUICQkRR48eleo55/q3zsaP827gefIr3jj/OiYTQoj/ZZJPRERERERE9HPBe7qJiIiIiIiI+giTbiIiIiIiIqI+wqSbiIiIiIiIqI8w6SYiIiIiIiLqI0y6iYiIiIiIiPoIk24iIiIiIiKiPsKkm4iIiIiIiKiPMOkmIiIiIiIi6iNMuomIiH4mMjMzMXjw4B7tm5KSgvj4+N4NqIcmT56MFStW6DsMiRAC8fHxsLKygkwmg1qt7rW2n2XMesORI0fw3HPPobW1VW8xEBENdEy6iYiox7777jv87ne/g5OTE0xMTGBra4vp06ejqKioV4/T35Kszug7SXrExcUFW7Zs6ZW2bty4gYyMDKxdu7ZX2vv/5siRI8jMzER2djZqa2sxevToNtv0l89Fd4WFhcHIyAiffPKJvkMhIhqw5PoOgIiIBq7IyEj8+OOP2LFjB0aMGIGbN2/i+PHjqK+v13do1Iu2bduGgIAAODs76zuUPtPS0gKZTAYDg+5fj9BoNLCzs0NAQEAfRKZ/CxYswLvvvotXXnlF36EQEQ1IvNJNREQ90tDQgMLCQmzYsAFTpkyBs7MzJkyYgDVr1uA3v/mNznZxcXGwtraGhYUFgoODUVZWJtWnpaXhueeew86dO+Hi4gJLS0vMnTsX9+7dA/DwD/6CggJkZGRAJpNBJpOhqqoKAPD1118jPDwcSqUSNjY2eOWVV1BXVye1PXnyZCxbtgyrVq2ClZUVbG1tkZaW1uY8Fi9eDBsbG5iammL06NHIzs6W6k+cOIHAwECYmZlh+PDhWLZsGX744Ydn6rdn6Q8AuHfvHqKjozFo0CDY2dlh8+bNOqsBJk+ejKtXryIxMVHqs8fl5uZCpVJBqVQiLCwMtbW1ncaclZWFiIgInbKn9W1VVVWbpdYNDQ2QyWTIz88HAOTn50MmkyE3Nxfe3t4wMzNDcHAwbt26hcOHD0OlUsHCwgLz5s1DY2OjzvGbm5uRkJAAS0tLDBs2DCkpKRBCSPUPHjxAcnIyHBwcMGjQIPj5+UnHBf575fngwYPw9PSEiYkJqqur2z3/goICTJgwASYmJrCzs8Mbb7yB5uZmAA8/n0uXLkV1dTVkMhlcXFza7J+fn4+FCxfizp070ng86qvvv/8eMTExGDJkCBQKBcLDw3H58uUOx+K7777DuHHjMGvWLDx48ACtra1IT0+Hq6srzMzMMHbsWOzZs0fn2DKZDMePH8e4ceOgUCgQEBCAiooKaZuysjJMmTIF5ubmsLCwgK+vL0pLS6X6iIgIlJaWQqPRdBgXERF1jEk3ERH1iFKphFKpxP79+/HgwYMOt3vppZekJOr06dPw8fFBSEgIbt++LW2j0Wiwf/9+ZGdnIzs7GwUFBVi/fj0AICMjA/7+/li0aBFqa2tRW1uL4cOHo6GhAcHBwfD29kZpaSmOHDmCmzdvYvbs2TrH37FjBwYNGoTi4mJs3LgR69atw7FjxwAAra2tCA8PR1FRET7++GNcuHAB69evh6GhoRRXWFgYIiMjUV5ejn/+8584ceIEEhISetxvz9ofAJCUlISioiIcPHgQx44dQ2FhIc6cOSPV79u3D46Ojli3bp3UZ480Njbiz3/+M3bu3IkvvvgC1dXVSE5O7jDe27dv48KFCxg3blybus76tjvS0tLw3nvv4eTJk6ipqcHs2bOxZcsW7Nq1Czk5OTh69Ci2bt3a5thyuRynTp1CRkYGNm3ahG3btkn1CQkJ+PLLL5GVlYXy8nK89NJLCAsL00loGxsbsWHDBmzbtg3nz5/HL37xizaxXb9+HTNmzMD48eNRVlaGv/71r/j73/+Ot99+G8DDz+e6devg6OiI2tpalJSUtGkjICAAW7ZsgYWFhTQej/p8wYIFKC0txcGDB/Hll19CCIEZM2bgp59+atNOTU0NAgMDMXr0aOzZswcmJiZIT0/HRx99hA8++ADnz59HYmIiXn75ZRQUFOjsu3btWrzzzjsoLS2FXC7Hq6++KtVFR0fD0dERJSUlOH36NN544w0YGRlJ9U5OTrCxsUFhYWGn40hERB0QREREPbRnzx4xZMgQYWpqKgICAsSaNWtEWVmZVF9YWCgsLCzE/fv3dfZzc3MTH374oRBCiNTUVKFQKMTdu3el+pUrVwo/Pz/p50mTJonly5frtPHWW2+JadOm6ZTV1NQIAKKiokLa79e//rXONuPHjxerV68WQgiRm5srDAwMpO2fFBsbK+Lj43XKCgsLhYGBgWhqamp3n+3btwtLS8t263qjP+7evSuMjIzEZ599JtU3NDQIhUKh00fOzs5i8+bNbWIDIK5cuSKVvf/++8LGxqbdeIUQ4uzZswKAqK6u1il/Wt9WVlYKAOLs2bNS/ffffy8AiLy8PCGEEHl5eQKA+Ne//iVtk56eLgAIjUYjlS1evFhMnz5d59gqlUq0trZKZatXrxYqlUoIIcTVq1eFoaGhuH79uk58ISEhYs2aNTp9oVarOzx3IYT4wx/+IDw8PHSO9f777wulUilaWlqEEEJs3rxZODs7d9pOe5+LS5cuCQCiqKhIKqurqxNmZmbi008/1dnvm2++EcOHDxfLli2TYrl//75QKBTi5MmTOu3GxsaKqKgoIUT7fZyTkyMASJ9hc3NzkZmZ2Wn83t7eIi0trdNtiIiofbzSTUREPRYZGYlvv/0WBw8eRFhYGPLz8+Hj44PMzEwAD5etarVaDB06VLoyrlQqUVlZqbNU1cXFBebm5tLPdnZ2uHXrVqfHLisrQ15enk67v/zlLwFAp20vLy+d/R5vW61Ww9HREe7u7h0eIzMzU+cY06dPR2trKyorK7veUY+196z98Z///Ac//fQTJkyYINVbWlrCw8OjSzEoFAq4ubm123Z7mpqaAACmpqZt6jrr2+54vB0bGxsoFAqMGDFCp+zJdidOnKizbN7f3x+XL19GS0sLzp07h5aWFri7u+v0c0FBgU4/GxsbtzmHJ128eBH+/v46x3r++eeh1Wpx7dq1bp/rk23L5XL4+flJZUOHDoWHhwcuXrwolTU1NSEwMBC//e1vpdssAODKlStobGzE1KlTdc7zo48+arMU/PHztLOzAwCpT5OSkhAXF4fQ0FCsX7++3WXkZmZmbZb4ExFR1/BBakRE9ExMTU0xdepUTJ06FSkpKYiLi0NqaioWLFgArVYLOzs7nXtpH3n8Sc6PL2UFAJlM9tSvKNJqtYiIiMCGDRva1D1KKp7WtpmZ2VOPsXjxYixbtqxNnZOTU6f7dtReX/VHV7XXtnjsXugnDRs2DMDDe4+tra2f2tajOB89kOzxtttbMv1kOzKZ7JnPX6vVwtDQEKdPn5ZuFXhEqVRK783MzNrc794fmZiYIDQ0FNnZ2Vi5ciUcHBwAPDxPAMjJyZHKHt/ncU/2MQCpT9PS0jBv3jzk5OTg8OHDSE1NRVZWFmbNmiXtc/v27TbjT0REXcOkm4iIepWnpyf2798PAPDx8cGNGzcgl8vbfcBUVxkbG6OlpUWnzMfHB3v37oWLiwvk8p79OvPy8sK1a9dw6dKldq92+/j44MKFCxg5cmSP2m+vvWftjxEjRsDIyAglJSVS4n/nzh1cunQJQUFB0nbt9VlPuLm5wcLCAhcuXOhwRUB7HiVotbW18Pb2BoBe/f7q4uJinZ+/+uorjBo1CoaGhvD29kZLSwtu3bqFwMDAZzqOSqXC3r17IYSQktWioiKYm5vD0dGxy+20Nx4qlQrNzc0oLi6WnnxeX1+PiooKeHp6StsZGBhg586dmDdvHqZMmYL8/HzY29vrPABu0qRJz3Se7u7ucHd3R2JiIqKiorB9+3Yp6b5//z40Go00jkRE1D1cXk5ERD1SX1+P4OBgfPzxxygvL0dlZSU+++wzbNy4ES+++CIAIDQ0FP7+/pg5cyaOHj2KqqoqnDx5EmvXrtV5OvLTuLi4oLi4GFVVVairq0NrayuWLFmC27dvIyoqCiUlJdBoNMjNzcXChQu7nGxOmjQJQUFBiIyMxLFjx1BZWYnDhw/jyJEjAIDVq1fj5MmTSEhIgFqtxuXLl3HgwIGnPkitpaUFarVa53Xx4sVe6Q9zc3PMnz8fK1euRF5eHs6fP4/Y2FgYGBjoXLV1cXHBF198gevXr+s80b27DAwMEBoaihMnTnRrPzMzM0ycOBHr16/HxYsXUVBQgD/+8Y89juNJ1dXVSEpKQkVFBXbv3o2tW7di+fLlAB4mkNHR0YiJicG+fftQWVmJU6dOIT09HTk5Od06zuuvv46amhosXboU33zzDQ4cOIDU1FQkJSV16+vFXFxcoNVqcfz4cdTV1aGxsRGjRo3Ciy++iEWLFuHEiRMoKyvDyy+/DAcHB2kOPWJoaIhPPvkEY8eORXBwMG7cuAFzc3MkJycjMTERO3bsgEajwZkzZ7B161bs2LGjS3E1NTUhISEB+fn5uHr1KoqKilBSUgKVSiVt89VXX8HExAT+/v5dPl8iIvovJt1ERNQjSqUSfn5+2Lx5M4KCgjB69GikpKRg0aJFeO+99wA8XMZ66NAhBAUFYeHChXB3d8fcuXNx9epV2NjYdPlYycnJMDQ0hKenJ6ytrVFdXQ17e3sUFRWhpaUF06ZNw5gxY7BixQoMHjy4W8nQ3r17MX78eERFRcHT0xOrVq2SknYvLy8UFBTg0qVLCAwMhLe3N/70pz/B3t6+0za1Wi28vb11XhEREb3WH5s2bYK/vz9eeOEFhIaG4vnnn4dKpdK573rdunWoqqqCm5vbMy8LjouLQ1ZWVreXuP/jH/9Ac3MzfH19sWLFCumJ370hJiYGTU1NmDBhApYsWYLly5cjPj5eqt++fTtiYmLw+9//Hh4eHpg5c6bO6oCucnBwwKFDh3Dq1CmMHTsWr732GmJjY7v9D4SAgAC89tprmDNnDqytrbFx40YpTl9fX7zwwgvw9/eHEAKHDh1qs8QeAORyOXbv3o1f/epX0lervfXWW0hJSUF6ejpUKhXCwsKQk5MDV1fXLsVlaGiI+vp6xMTEwN3dHbNnz0Z4eDjefPNNaZvdu3cjOjoaCoWiW+dMREQPyURnN3IRERFRv/fDDz/AwcEB77zzDmJjY3u9fSEE/Pz8pKXH9PNRV1cHDw8PlJaWdjmRJyIiXbzSTURENMCcPXsWu3fvlpYTR0dHA0CbJcm9RSaT4W9/+xuam5v7pH3qv6qqqvCXv/yFCTcR0TPglW4iIqIB5uzZs4iLi0NFRQWMjY3h6+uLTZs2YcyYMfoOjYiIiJ7ApJuIiIiIiIioj3B5OREREREREVEfYdJNRERERERE1EeYdBMRERERERH1ESbdRERERERERH2ESTcRERERERFRH2HSTURERERERNRHmHQTERERERER9REm3URERERERER9hEk3ERERERERUR/5P1o14wwPx/BPAAAAAElFTkSuQmCC",
            "text/plain": [
              "<Figure size 1000x600 with 1 Axes>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "# 读取训练集目标文件并分析句子长度\n",
        "with open(\"wmt16/train_trg.bpe\", \"r\", encoding=\"utf8\") as file:\n",
        "    lines = file.readlines()\n",
        "\n",
        "# 分割每行并计算长度\n",
        "lengths = [len(line.strip().split()) for line in lines]\n",
        "\n",
        "# 创建句子长度的直方图\n",
        "plt.figure(figsize=(10, 6))\n",
        "plt.hist(lengths, bins=50, alpha=0.7, color='blue')\n",
        "plt.xlabel('Sentence Length (number of tokens)')\n",
        "plt.ylabel('Frequency')\n",
        "plt.title('Distribution of Sentence Lengths in Training Data')\n",
        "plt.grid(True, alpha=0.3)\n",
        "\n",
        "# 添加一些统计信息作为文本\n",
        "plt.axvline(np.mean(lengths), color='r', linestyle='dashed', linewidth=1, label=f'Mean: {np.mean(lengths):.2f}')\n",
        "plt.axvline(np.median(lengths), color='g', linestyle='dashed', linewidth=1, label=f'Median: {np.median(lengths):.2f}')\n",
        "plt.legend()\n",
        "\n",
        "# 显示一些统计信息\n",
        "print(f\"Total sentences: {len(lengths)}\")\n",
        "print(f\"Min length: {min(lengths)}\")\n",
        "print(f\"Max length: {max(lengths)}\")\n",
        "print(f\"Mean length: {np.mean(lengths):.2f}\")\n",
        "print(f\"Median length: {np.median(lengths)}\")\n",
        "\n",
        "plt.tight_layout()\n",
        "plt.show()\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "bbd86f3e4db77521",
      "metadata": {
        "ExecuteTime": {
          "end_time": "2025-07-11T08:05:12.693773Z",
          "start_time": "2025-07-11T08:05:12.554874Z"
        },
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 702
        },
        "id": "bbd86f3e4db77521",
        "outputId": "7c91f47d-9a75-45c7-b9ac-5e4a66e22f01"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Total sentences: 29000\n",
            "Min length: 16\n",
            "Max length: 215\n",
            "Mean length: 63.07\n",
            "Median length: 60.0\n"
          ]
        },
        {
          "data": {
            "image/png": "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N+vhhx/Wd999p9tuu63czPr163X55ZerXbt2evLJJ+Xv768tW7Zo+fLlkqRWrVrpySef1GOPPaaRI0eqe/fukqQLLrjAs46DBw+qX79+uuGGGzR48GBFR0efsF3//Oc/5XA49NBDD2nfvn2aMmWKevfurTVr1lRqVMdM2/7KMAxdccUVWrRokUaMGKEOHTpo7ty5euCBB7Rnzx69+OKLXvlly5bp008/1V133aXQ0FC9/PLLGjhwoFJSUsoUun+Vl5ennj17asuWLRo9erQSExM1a9YsDRs2TBkZGbrnnnvUqlUrvfvuuxozZowaNmyo++67T5IUGRlZ7joTEhIkSe+//74uvPDCE45Ipqen6/zzz/cUS5GRkfrmm280YsQIZWVllbmB27PPPiun06n7779fmZmZmjhxogYNGqQff/xRkvTII48oMzNTu3fv9uyjkJAQSUdP073iiiu0bNkyjRw5Uq1atdK6dev04osvatOmTfr8888rvU/37t2r8847TxkZGRo5cqRatmypPXv26JNPPtGRI0fkcrl05MgR9ejRQ3v27NHtt9+uRo0aacWKFRo3bpxSU1Or5Xr0d999V0OHDlVSUpKee+45HTlyRK+99pq6deumX3/91euPDyUlJUpKSlKXLl30wgsvaP78+Zo0aZKaNm2qO++807OvkpOT9dNPP+nOO+9Uy5Yt9cUXX2jo0KFe27399tu1d+9ezZs3T++++265bfvggw+UnZ2t22+/XQ6HQxMnTtSAAQO0bds2z5keAwcO1Pr163X33XercePG2rdvn+bNm6eUlJQqnXpc1ePBrGuvvVbNmzfXM8884/lD2Lx587Rt2zYNHz5cMTExWr9+vV5//XWtX79eP/zwQ4WnlW/ZskXXXHONRowYoaFDh+qtt97SsGHD1LlzZ7Vp0+aEyx4+fFh9+/bVgAEDdN111+mTTz7RQw89pLZt26pfv36Sjv4h75JLLlFqaqruuecexcTE6IMPPtCiRYtOen9I5X+Gm9knAwYM0KZNm/Thhx/qxRdfVP369SX97/PltddeU5s2bXTFFVfI19dXs2fP1l133SW3261Ro0ZVS9sBnAYMAIBhGIYxffp0Q5Lx888/HzcTHh5udOzY0fP68ccfN/76Ufriiy8akoz9+/cfdx0///yzIcmYPn16mXk9evQwJBnTpk0rd16PHj08rxctWmRIMho0aGBkZWV5ps+cOdOQZLz00kueaQkJCcbQoUMrXOeJ2jZ06FAjISHB8/rzzz83JBlPP/20V+6aa64xHA6HsWXLFs80SYbL5fKa9ttvvxmSjFdeeaXMtv5qypQphiTjvffe80wrLCw0unbtaoSEhHi994SEBKN///4nXJ9hGIbb7fbs6+joaOPGG280pk6dauzcubNMdsSIEUZsbKxx4MABr+k33HCDER4ebhw5csQwjP/1R6tWrYyCggJP7qWXXjIkGevWrfNM69+/v9e+LPXuu+8aTqfT+P77772mT5s2zZBkLF++3DPN7D4dMmSI4XQ6y/25drvdhmEYxlNPPWUEBwcbmzZt8pr/97//3fDx8TFSUlLKLPtXPXr0MNq0aXPc+dnZ2UZERIRx2223eU1PS0szwsPDvaYPHTrUkGQ8+eSTXtmOHTsanTt39rz+73//a0gypkyZ4plWUlJiXHLJJWV+hkeNGmWU9yvP9u3bDUlGvXr1jEOHDnmmf/HFF4YkY/bs2YZhGMbhw4cNScbzzz9/wv1QnmM/Iwzj5I6Hv5o1a5YhyVi0aFGZ7d14441l8qU/q3/14YcfGpKMpUuXeqaVfhZu377dMy0hIaFMbt++fYa/v79x3333eaaVHgd/bVPpsfbOO+94phUUFBgxMTHGwIEDPdMmTZpkSDI+//xzz7S8vDyjZcuWZdZZnqp8hpvdJ88//3yZfXKidSQlJRlNmjQ5YXsBnFk41RwAKiEkJOSEd8aNiIiQJH3xxRdVPkXX399fw4cPN50fMmSIQkNDPa+vueYaxcbG6uuvv67S9s36+uuv5ePjo7/97W9e0++77z4ZhqFvvvnGa3rv3r3VtGlTz+t27dopLCxM27Ztq3A7MTExuvHGGz3T/Pz89Le//U05OTlasmRJpdvucDg0d+5cPf3006pTp44+/PBDjRo1SgkJCbr++us913gbhqH//ve/Sk5OlmEYOnDggOcrKSlJmZmZWr16tde6hw8f7nU9fumZAxW9T0maNWuWWrVqpZYtW3pt65JLLpGkMiN/Fe1Tt9utzz//XMnJyV7XvP51P5Rut3v37qpTp47Xdnv37q2SkhItXbq0wrafyLx585SRkaEbb7zRa/0+Pj7q0qVLuSOad9xxh9fr7t27e+3Db7/9Vn5+fl5nnzidziqNMF5//fWqU6eO17ak//VZYGCgXC6XFi9erMOHD1d6/eWp6vFg1rH7T5LXGTD5+fk6cOCAzj//fEkq83NcntatW3v2jXR0xLdFixam2hwSEqLBgwd7XrtcLp133nll+rRBgwa64oorPNMCAgKOe4ZRVRz7GX6y++TYdWRmZurAgQPq0aOHtm3bpszMzGpqOYDajlPNAaAScnJyFBUVddz5119/vd544w3deuut+vvf/65evXppwIABuuaaa0zf4bdBgwaVupFa8+bNvV47HA41a9bM8jtm79y5U3FxcV5FvyTP3ZV37tzpNb1Ro0Zl1lGnTp0KC5mdO3eqefPmZfbf8bZjlr+/vx555BE98sgjSk1N1ZIlS/TSSy9p5syZ8vPz03vvvaf9+/crIyNDr7/+ul5//fVy17Nv3z6v18e+z9KCzkzBtnnzZv3xxx/HPUW+om2Vbq90W/v371dWVlaFj/ravHmz1q5da3q7lbV582ZJ8vwB4VhhYWFerwMCAsq05diflZ07dyo2NlZBQUFeuWbNmlW6fRX1mb+/v5577jndd999io6O1vnnn6/LL79cQ4YMUUxMTKW3V942S7dbXYV9YmJimWmHDh3SE088oY8++qhMn5opEE+mzQ0bNixzKnudOnW0du1az+udO3eqadOmZXJV6dPjOfYz/GT3iSQtX75cjz/+uFauXKkjR46UWUd4ePjJNxxArUfhDQAm7d69W5mZmSf8JTAwMFBLly7VokWLNGfOHH377bf6+OOPdckll+i7774zdadgK+62e7xrN0tKSqp89+LKOt52DBs81TI2NlY33HCDBg4cqDZt2mjmzJmaMWOG56yFwYMHl7l2uNSxjyY6mffpdrvVtm1bTZ48udz58fHx1batY7d76aWX6sEHHyx3/llnnVWp9ZW3funodd7lFarHXmN/qn4mK9reX/fjvffeq+TkZH3++eeaO3euHn30UU2YMEELFy5Ux44dLdnmySjvc+S6667TihUr9MADD6hDhw4KCQmR2+1W3759TZ2hczJttsPxX95n+Mnuk61bt6pXr15q2bKlJk+erPj4eLlcLn399dd68cUXq/XmhABqNwpvADCp9MZMSUlJJ8w5nU716tVLvXr10uTJk/XMM8/okUce0aJFi9S7d+9KPxe3IqWjiaUMw9CWLVu8CsI6deqU+4isnTt3qkmTJp7XlWlbQkKC5s+fr+zsbK9R7z///NMzvzokJCRo7dq1crvdXqPe1b0d6egp7O3atdPmzZt14MABRUZGKjQ0VCUlJerdu3e1bed4+7lp06b67bff1KtXr2r5OYmMjFRYWFiFz9du2rSpcnJyqvU9Hrt+SYqKiqq2bSQkJGjRokWex+2V+usd5EtV1zHXtGlT3Xfffbrvvvu0efNmdejQQZMmTfK6S7ZdHT58WAsWLNATTzyhxx57zDP92M+PmpSQkKANGzbIMAyvPiuvT6vi2M/wyuyT4/0MzZ49WwUFBfryyy+9zgiorhvCATh9cI03AJiwcOFCPfXUU0pMTNSgQYOOmzt06FCZaR06dJAkz+OgSp+nW13Pin7nnXe8rln85JNPlJqa6rlTsHS0YPjhhx+8Hh/11VdflXnsWGXadtlll6mkpESvvvqq1/QXX3xRDofDa/sn47LLLlNaWpo+/vhjz7Ti4mK98sorCgkJUY8ePSq9zs2bNyslJaXM9IyMDK1cuVJ16tRRZGSkfHx8NHDgQP33v/8tt3jdv39/pbctHd3P5Z3Get1112nPnj36z3/+U2ZeXl6ecnNzK7Udp9Opq666SrNnz9Yvv/xSZn7paON1112nlStXau7cuWUyGRkZKi4urtR2j5WUlKSwsDA988wzKioqKjO/KvsxKSlJRUVFXvvK7XZ7Hh32Vyd7zB05ckT5+fle05o2barQ0NAyj3mzq9IR52NHmKvjjvXVJSkpSXv27NGXX37pmZafn1/u8VBZ5X2GV2afHO9nqLx1ZGZmavr06SfdZgCnF0a8AeAY33zzjf78808VFxcrPT1dCxcu1Lx585SQkKAvv/xSAQEBx132ySef1NKlS9W/f38lJCRo3759+te//qWGDRt6nqXbtGlTRUREaNq0aQoNDVVwcLC6dOlS7jWZZtStW1fdunXT8OHDlZ6erilTpqhZs2ZeNyS69dZb9cknn6hv37667rrrtHXrVr333nteN3eqbNuSk5N18cUX65FHHtGOHTvUvn17fffdd/riiy907733lll3VY0cOVL//ve/NWzYMK1atUqNGzfWJ598ouXLl2vKlCllrjE347ffftNNN92kfv36qXv37qpbt6727Nmjt99+W3v37tWUKVM8v1A/++yzWrRokbp06aLbbrtNrVu31qFDh7R69WrNnz+/3D+2VKRz5876+OOP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Srm53vMaN5bq1pX275d27fKeFxoqNW9epWYOHjxY48aN086dOyVJy5cv14cffqhFixZ5MgUFBXrmmWc0f/58de3aVZLUpEkTLVu2TP/+97/Vo0cP+fn56YknnvAsk5iYqJUrV2rmzJm67rrr/rIL6ujVV1+Vj4+PWrZsqf79+2vBggW67bbbJEn169dX06ZNj9veffv2KScnR88++6yefvppPffcc/r22281YMAALVq0SD169PBk//Wvf+nBBx9Ubm6uWrRooXnz5snlcpW73rT/v1dPdHS01/To6GjPvGO9+eabSkpKUsOGDY/b3ppE4Q3A1iICInRN62sUERBhcoEI6Zprjn4HAACQpH//W/pLISpJGjRIeu89afduqXPnsssYxtHvw4ZJP/zgPe/dd6XBg6WZM6XRo73n9ekjzZ1bpWZGRkaqf//+mjFjhgzDUP/+/VW/fn2vzJYtW3TkyBFdeumlXtMLCwvVsWNHz+upU6fqrbfeUkpKivLy8lRYWKgOHTp4LdOmTRv5+Ph4XsfGxmrdunWe16NHj9boY9/fX7jdbknSlVdeqTFjxkiSOnTooBUrVmjatGlehfegQYN06aWXKjU1VS+88IKuu+46LV++3Ota8KravXu35s6dW2ZE304ovAHYWpM6TTTr2lmVWKCJNKsSeQAAcPq7/fayjxutU+fo94YNpVWrjr/sjBnlj3hL0nXXSf8/6uwRGnoyLdUtt9ziKXanTp1aZn5OTo4kac6cOWrQoIHXPH9/f0nSRx99pPvvv1+TJk1S165dFRoaqueff14//vijV97Pz8/rtcPh8BTTZtSvX1++vr5q3bq11/RWrVpp2bJlXtPCw8MVHh6u5s2b6/zzz1edOnX02Wef6cYbbyyz3piYGElSenq6YmNjPdPT09PL/PFAkqZPn6569erpChs/UpbCG4CtFZYUal/uPkUFR8nlU/7pSN4LFEr79klRUdJxTl8CAABnmNjYo1/lCQj432nl5WnR4vjzIiOPflWjvn37qrCwUA6HQ0lJSWXmt27dWv7+/kpJSfEaUf6r5cuX64ILLtBdd93lmbZ169Zqbad09AZn5557rjZu3Og1fdOmTUpISDjucoZhyDAMFRQUlDs/MTFRMTExWrBggafQzsrK0o8//qg777yzzLqmT5+uIUOGlPlDgp1wczUAtvb7vt8V/2K8ft/3u8kFfpfi449+BwAAqGV8fHz0xx9/aMOGDV6ngZcKDQ3V/fffrzFjxujtt9/W1q1btXr1ar3yyit6++23JUnNmzfXL7/8orlz52rTpk169NFHq/Rs61dffVW9evU6YeaBBx7Qxx9/rP/85z/asmWLXn31Vc2ePdtT9G/btk0TJkzQqlWrlJKSohUrVujaa69VYGCgLrvsMs96WrZsqc8++0zS0ZH3e++9V08//bS+/PJLrVu3TkOGDFFcXJyuuuoqr+0vXLhQ27dv16233lrp93cqMeINAAAAADYSFhZ2wvlPPfWUIiMjNWHCBG3btk0RERHq1KmTHn74YUnS7bffrl9//VXXX3+9HA6HbrzxRt1111365ptvKtWOAwcOVDhSfvXVV2vatGmaMGGC/va3v6lFixb673//q27dukmSAgIC9P3332vKlCk6fPiwoqOjddFFF2nFihVejxzbuHGjMjMzPa9Lb8Q2cuRIZWRkqFu3bvr222/LXBP+5ptv6oILLlDLli0r9d5ONYdhlN41AMeTlZWl8PBwZWZmVngQwJvb7da+ffsUFRUlp5MTLE6l5OQTz3c43IqP36ddu6JkGOX3zezZFjSsklanrlbn1ztr1chV6hR7gtPAPAusPnqDlFWrTnzamM1x7NgXfWNv9I990Tf2dTr1TX5+vrZv367ExMRquWmXHRiGoeLiYvn6+try+dSnuxP9TFWmTqzdRxYAAAAAADZH4Q0AAAAAgIW4xhuArXWI6aD8R/Ll52PyLpUdOkj5+ZKN72oJAACAMwuFNwBbczqc8vf1r8QCTsm/EnkAAADAYpxqDsDWNh3cpJ4zemrTwU0mF9gk9ex59DsAAABgA4x4Aziuiu6MXpHquCt6TmGOluxcopzCHJML5EhLlhz9DgAAANgAI94AAAAAAFiIwhsAAAAAAAtReAMAAAAAYCEKbwC21ii8kf6T/B81Cm9kcoFG0n/+c/Q7AAAAJEmLFy+Ww+FQRkaGJGnGjBmKiIio0TadSSi8Adha/aD6urXTraofVN/kAvWlW289+h0AAKAWGDZsmBwOh+64444y80aNGiWXy6Xhw4dX6zavv/56barBp8DMmTNHXbp0UWBgoOrUqaOrrrrKa35KSor69++voKAgRUVF6YEHHlBxcfEJ13no0CENGjRIYWFhioiI0IgRI5RzzA13165dq+7duysgIEDx8fGaOHFidb+1clF4A7C1A0cO6I3Vb+jAkQMmFzggvfHG0e8AAAC1RHx8vD766CPl5eV5puXn5+vDDz9UIwvO5AsMDFRUVFS1r9eM//73v7r55ps1fPhw/fbbb1q+fLluuukmz/ySkhL1799fhYWFWrFihd5++23NmDFDjz322AnXO2jQIK1fv17z5s3TV199paVLl2rkyJGe+VlZWerTp48SEhK0atUqPf/88xo/frxef/11y95rKQpvALaWkpmi22bfppTMFJMLpEi33Xb0OwAAQC3RqVMnxcfH69NPP/VM+/TTT9WoUSO1b9/eK+t2uzVhwgQlJiYqMDBQ7du31yeffOKV+frrr3XWWWcpMDBQF198sXbs2OE1/9hTzbdu3aorr7xS0dHRCgkJ0bnnnqv58+d7LdO4cWM988wzuuWWWxQaGqpGjRpVumgtLi7WPffco+eff1533HGHzjrrLLVu3VrXXXedJ/Pdd99pw4YNeu+999ShQwf169dPTz31lKZOnarCwsJy1/vHH3/o22+/1RtvvKEuXbqoW7dueuWVV/TRRx9p7969kqT3339fhYWFeuutt9SmTRvdcMMN+tvf/qbJkydX6j1UBYU3AAAAANjALbfcounTp3tev/XWWxo2bFiZ3IQJE/TOO+9o2rRpWr9+vcaMGaPBgwdryZIlkqRdu3ZpwIABSk5O1po1a3Trrbfq73//+wm3nZOTo8suu0wLFizQr7/+qr59+yo5OVkpxwxmTJo0Seecc45+/fVX3XXXXbrzzju1ceNGz/yePXuW2+ZSq1ev1p49e+R0OtWxY0fFxsaqX79++v333z2ZlStXqm3btoqOjvZMS0pKUlZWltavX1/ueleuXKmIiAidc845nmm9e/eW0+nUjz/+6MlcdNFFcrlcXuvduHGjDh8+fML9c7J8LV07AAAAANSw1OxUpeakek2rE1BHiXUSlV+crw37N5RZplNsJ0nSxgMblVuU6zWvcURj1Q2sq/25+7Ura5fXvFBXqJrXa16ldg4ePFjjxo3Tzp07JUnLly/Xhx9+qEWLFnkyBQUFeuaZZzR//nx17dpVktSkSRMtW7ZM//73v9WjRw+99tpratq0qSZNmiRJatGihdatW6fnnnvuuNtu376918j6U089pc8++0xffvmlRo8e7Zl+2WWX6a677pIkPfTQQ3rxxRe1aNEitWjRQpLUqFEjxcbGHnc727ZtkySNHz9ekydPVuPGjTVp0iT17NlTmzZtUt26dZWWluZVdEvyvE5LSyt3vWlpaWVOnff19fWsrzSTmJh43PXWqVPnuO0+WRTeAAAAAE5r/171bz2x5AmvaYPaDtJ7A97T7qzd6vx65zLLGI8bkqRhXwzTD7t/8Jr37tXvanC7wZq5fqZGfzPaa16fpn00d/DcKrUzMjJS/fv314wZM2QYhvr376/6x9wwdsuWLTpy5IguvfRSr+mFhYXq2LGjpKOnXXfp0sVrfmmRfjw5OTkaP3685syZo9TUVBUXFysvL6/MiHe7du08/3Y4HIqJidG+ffs80955550TbsftdkuSHnnkEQ0cOFCSNH36dDVs2FCzZs3S7bfffsLla6saLbwnTJigTz/9VH/++acCAwN1wQUX6LnnnvP8tUQ6eqpC6SkTpW6//XZNmzbN8zolJUV33nmnFi1apJCQEA0dOlQTJkyQr+//3t7ixYs1duxYrV+/XvHx8frHP/5xwlMgANhDiCtEPRJ6KMQVYnKBEKlHj6PfAQAAJN3e+XZd0eIKr2l1Ao6ObjYMa6hVI1cdd9kZV84od8Rbkq5rc526xnsXtKGu0JNq6y233OIZYZ46dWqZ+aV36Z4zZ44aNGjgNc/f37/K273//vs1b948vfDCC2rWrJkCAwN1zTXXlLmm2s/Pz+u1w+HwFNNmlI6Gt27d2qvdTZo08RT5MTEx+umnn7yWS09P98wrz7F/AJCOXk9+6NAhzzIxMTGe9Zhdb3Wp0cJ7yZIlGjVqlM4991wVFxfr4YcfVp8+fbRhwwYFBwd7crfddpuefPJJz+ugoCDPv0vveBcTE6MVK1YoNTVVQ4YMkZ+fn5555hlJ0vbt29W/f3/dcccdev/997VgwQLdeuutio2NVVJS0ql7wwAq7ax6Z2nxsMWVWOAsaXEl8gAA4LQXGxqr2NDyT38O8A3wnFZenhb1Wxx3XmRwpCKDI0+6fX/Vt29fFRYWyuFwlFurtG7dWv7+/kpJSVGPHj3KXUerVq305Zdfek374Ycfys2WWr58uYYNG6arr75a0tEC/9gbslWHzp07y9/fXxs3blS3bt0kSUVFRdqxY4cSEhIkHR2d/+c//6l9+/Z5Th+fN2+ewsLCvAr2v+ratasyMjK0atUqde589AyGhQsXyu12e0b/u3btqkceeURFRUWePyDMmzdPLVq0sPQ0c6mGb6727bffatiwYWrTpo3at2+vGTNmKCUlRatWef/FKSgoSDExMZ6vsLAwzzwzd7ybNm2aEhMTNWnSJLVq1UqjR4/WNddcoxdffPGUvl8Alec23CooLpDbMPmXVLdbKig4+h0AAKCW8fHx0R9//KENGzbIx8enzPzQ0FDdf//9GjNmjN5++21t3bpVq1ev1iuvvKK3335bknTHHXdo8+bNeuCBB7Rx40Z98MEHmjFjxgm327x5c3366adas2aNfvvtN910002VGskuNWTIEI0bN+6488PCwnTHHXfo8ccf13fffaeNGzfqzjvvlCRde+21kqQ+ffqodevWuvnmm/Xbb79p7ty5+sc//qFRo0Z5RvV/+ukntWzZUnv27JF09I8Nffv21W233aaffvpJy5cv1+jRo3XDDTcoLi5OknTTTTfJ5XJpxIgRWr9+vT7++GO99NJLGjt2bKXfZ2XZ6hrvzMxMSVLdunW9pr///vt67733FBMTo+TkZD366KOeUe/j3fHuzjvv1Pr169WxY0etXLlSvXv39lpnUlKS7r333nLbUVBQoIKCAs/rrKwsSUevR6jKD9+ZzO12yzAM9lsNcDgqmu+Ww2HI4bCub6qj21enrta5b5yrn2/9+YR/jf7fAqvlPPdcuX/+WepkIm9THDv2Rd/YG/1jX/SNfZ1OfVP6Xkq/apvSNoeGhnq9Pnb+k08+qfr162vChAnatm2bIiIi1KlTJ40bN06GYSg+Pl6ffPKJxo4dq1deeUXnnXee/vnPf2rEiBFl9k/p90mTJmnEiBG64IILVL9+fT344IPKysoqsy/L27d/nZaSkiKn03nC/T9x4kT5+Pjo5ptvVl5enrp06aIFCxYoIiJChmHI6XRq9uzZuuuuu9S1a1cFBwdryJAheuKJJzzrzc3N1caNG1VYWOiZ9t577+nuu+9Wr1695HQ6NWDAAL388sue+WFhYZo7d65Gjx6tzp07q379+nr00Ud12223Hbe9pe+tvFqwMseMw7DJT6Tb7dYVV1yhjIwMLVu2zDP99ddfV0JCguLi4rR27Vo99NBDOu+88zzPtxs5cqR27typuXP/dwODI0eOKDg4WF9//bX69euns846S8OHD/f6y8vXX3+t/v3768iRIwoM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FqLwBgAAAADAQhTeAAAAAABYiMIbgK35loQrOiNZviXhpvK5vuH6MTpZub7m8gAAAIDVeJwYAFsLLmiqc7d8aTqfFtxUT59rPg8AAABYjRFvALbmdhSpwHe/3I4iU3kfd5HCCvbLx20uDwAAAFiNwhuArWUHrtO8DlHKDlxnKt84e53enxelxtnm8gAAAIDVKLwBAAAAALAQhTcAAAAAABai8AYAAAAAwEIU3gAAAAAAWIjHiQGwtbAj7ZW0OlO+7mBT+e1h7XVdUqYKfM3lAQAAAKtReAOwNYd85OcOM513O3yU52c+DwAAAFiNU80B2FqO/2b92DxJOf6bTeVjczbriR+TFJtjLg8AAABYjRFvALZW4pOt/eHfqcQn21Q+qCRbnfZ/p6ASc/lTITm58ss4HFJ8vLRrl2QY0uzZ1d8uAAAAnBqMeAMAAAAAYCEKbwAAAAAALEThDQAAAACAhSi8AdhaQGG8zt75qgIK403l9wfE67WzX9X+AHN5AAAAwGpVKry3bdtW3e0AgHL5F0eq8f5R8i+ONJXP8o/U141HKcvfXB4AAACwWpUK72bNmuniiy/We++9p/z8/OpuEwB4FPoc0u6676nQ55CpfEjhIfXc/Z5CCs3lAQAAAKtVqfBevXq12rVrp7FjxyomJka33367fvrpp+puGwAoz3+H1jS5WXn+O0zlo/N26L41Nys6z1weAAAAsFqVCu8OHTropZde0t69e/XWW28pNTVV3bp109lnn63Jkydr//791d1OAAAAAABqpZO6uZqvr68GDBigWbNm6bnnntOWLVt0//33Kz4+XkOGDFFqamp1tRMAAAAAgFrppArvX375RXfddZdiY2M1efJk3X///dq6davmzZunvXv36sorr6yudgIAAAAAUCtVqfCePHmy2rZtqwsuuEB79+7VO++8o507d+rpp59WYmKiunfvrhkzZmj16tUnXM/SpUuVnJysuLg4ORwOff75517zhw0bJofD4fXVt29fr8yhQ4c0aNAghYWFKSIiQiNGjFBOTo5XZu3aterevbsCAgIUHx+viRMnVuVtA6gBPiXBisg5Xz4lwaby+T7B+jPifOX7mMsDAAAAVvOtykKvvfaabrnlFg0bNkyxsbHlZqKiovTmm2+ecD25ublq3769brnlFg0YMKDcTN++fTV9+nTPa39/f6/5gwYN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mzdPRUVF6tOnj3Jzc71yt912m1JTUz1fEydOrKEWn3natGnjte+XLVvmmTdmzBjNnj1bs2bN0pIlS7R3714NGDCgBlt75vj555+9+mXevHmSpGuvvdaT4bg5NXJzc9W+fXtNnTq13PkTJ07Uyy+/rGnTpunHH39UcHCwkpKSlJ+f78kMGjRI69ev17x58/TVV19p6dKlGjly5Kl6C6e1E/XPkSNHtHr1aj366KNavXq1Pv30U23cuFFXXHFFmeyTTz7pdTzdfffdp6L5p7WKjh1J6tu3r9d+//DDD73mc+xYp6L++Wu/pKam6q233pLD4dDAgQO9chw71c/M788V/Y5WUlKi/v37q7CwUCtWrNDbb7+tGTNm6LHHHquJt4SKGEA127dvnyHJWLJkiWdajx49jHvuuafmGnUGe/zxx4327duXOy8jI8Pw8/MzZs2a5Zn2xx9/GJKMlStXnqIWotQ999xjNG3a1HC73YZhcNzUFEnGZ5995nntdruNmJgY4/nnn/dMy8jIMPz9/Y0PP/zQMAzD2LBhgyHJ+Pnnnz2Zb775xnA4HMaePXtOWdvPBMf2T3l++uknQ5Kxc+dOz7SEhATjxRdftLZxZ7jy+mbo0KHGlVdeedxlOHZOHTPHzpVXXmlccsklXtM4dk6NY39/NvM72tdff204nU4jLS3Nk3nttdeMsLAwo6Cg4NS+AVSIEW9Uu8zMTElS3bp1vaa///77ql+/vs4++2yNGzdOR44cqYnmnZE2b96suLg4NWnSRIMGDVJKSookadWqVSoqKlLv3r092ZYtW6pRo0ZauXJlTTX3jFRYWKj33ntPt9xyixwOh2c6x03N2759u9LS0ryOk/DwcHXp0sVznKxcuVIRERE655xzPJnevXvL6XTqxx9/POVtPtNlZmbK4XAoIiLCa/qzzz6revXqqWPHjnr++ec5HfMUWbx4saKiotSiRQvdeeedOnjwoGcex459pKena86cORoxYkSZeRw71jv292czv6OtXLlSbdu2VXR0tCeTlJSkrKwsrV+//hS2Hmb41nQDcHpxu9269957deGFF+rss8/2TL/pppuUkJCguLg4rV27Vg899JA2btyoTz/9tAZbe2bo0qWLZsyYoRYtWig1NVVPPPGEunfvrt9//11paWlyuVxlfjmNjo5WWlpazTT4DPX5558rIyNDw4YN80zjuLGH0mPhr7/YlL4unZeWlqaoqCiv+b6+vqpbty7H0imWn5+vhx56SDfeeKPCwsI80//2t7+pU6dOqlu3rlasWKFx48YpNTVVkydPrsHWnv769u2rAQMGKDExUVu3btXDDz+sfv36aeXKlfLx8eHYsZG3335boaGhZS4349ixXnm/P5v5HS0tLa3c/5tK58FeKLxRrUaNGqXff//d6xpiSV7XarVt21axsbHq1auXtm7dqqZNm57qZp5R+vXr5/l3u3bt1KVLFyUkJGjmzJkKDAyswZbhr958803169dPcXFxnmkcN0DlFBUV6brrrpNhGHrttde85o0dO9bz73bt2snlcun222/XhAkT5O/vf6qbesa44YYbPP9u27at2rVrp6ZNm2rx4sXq1atXDbYMx3rrrbc0aNAgBQQEeE3n2LHe8X5/xumFU81RbUaPHq2vvvpKixYtUsOGDU+Y7dKliyRpy5Ytp6Jp+IuIiAidddZZ2rJli2JiYlRYWKiMjAyvTHp6umJiYmqmgWegnTt3av78+br11ltPmOO4qRmlx8Kxd5L963ESExOjffv2ec0vLi7WoUOHOJZOkdKie+fOnZo3b57XaHd5unTpouLiYu3YsePUNBCSpCZNmqh+/fqezzGOHXv4/vvvtXHjxgr/H5I4dqrb8X5/NvM7WkxMTLn/N5XOg71QeOOkGYah0aNH67PPPtPChQuVmJhY4TJr1qyRJMXGxlrcOhwrJydHW7duVWxsrDp37iw/Pz8tWLDAM3/jxo1KSUlR165da7CVZ5bp06crKipK/fv3P2GO46ZmJCYmKiYmxus4ycrK0o8//ug5Trp27aqMjAytWrXKk1m4cKHcbrfnDyawTmnRvXnzZs2fP1/16tWrcJk1a9bI6XSWOc0Z1tq9e7cOHjzo+Rzj2LGHN998U507d1b79u0rzHLsVI+Kfn828zta165dtW7dOq8/XpX+4bF169an5o3ANE41x0kbNWqUPvjgA33xxRcKDQ31XFMSHh6uwMBAbd26VR988IEuu+wy1atXT2vXrtWYMWN00UUXqV27djXc+tPf/fffr+Tk5P9r7/6jar7/OIA/b7/vdasVLSnKr9pthvIjZUUJtTMba0MiWoWRHzU/Rys/zoozv2Y227GVmbFhx5xCM6dakhTKJkIr+RFWhBTT7f39w/H5ukoq3WU8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",
            "text/plain": [
              "<Figure size 1000x600 with 1 Axes>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "# 读取训练集目标文件并分析句子长度\n",
        "with open(\"wmt16/train_trg.bpe\", \"r\", encoding=\"utf8\") as file:\n",
        "    lines = file.readlines()\n",
        "\n",
        "# 分割每行并计算长度\n",
        "lengths = [len(line.strip()) for line in lines]\n",
        "\n",
        "# 创建句子长度的直方图\n",
        "plt.figure(figsize=(10, 6))\n",
        "plt.hist(lengths, bins=50, alpha=0.7, color='blue')\n",
        "plt.xlabel('Sentence Length (number of tokens)')\n",
        "plt.ylabel('Frequency')\n",
        "plt.title('Distribution of Sentence Lengths in Training Data')\n",
        "plt.grid(True, alpha=0.3)\n",
        "\n",
        "# 添加一些统计信息作为文本\n",
        "plt.axvline(np.mean(lengths), color='r', linestyle='dashed', linewidth=1, label=f'Mean: {np.mean(lengths):.2f}')\n",
        "plt.axvline(np.median(lengths), color='g', linestyle='dashed', linewidth=1, label=f'Median: {np.median(lengths):.2f}')\n",
        "plt.legend()\n",
        "\n",
        "# 显示一些统计信息\n",
        "print(f\"Total sentences: {len(lengths)}\")\n",
        "print(f\"Min length: {min(lengths)}\")\n",
        "print(f\"Max length: {max(lengths)}\")\n",
        "print(f\"Mean length: {np.mean(lengths):.2f}\")\n",
        "print(f\"Median length: {np.median(lengths)}\")\n",
        "\n",
        "plt.tight_layout()\n",
        "plt.show()\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "00f8629e",
      "metadata": {
        "id": "00f8629e"
      },
      "source": [
        "# LangPairDataset"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "30745b5f",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "30745b5f",
        "outputId": "b24896af-d565-496f-f627-d23714edd825"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "save cache to wmt16/.cache/de2en_train_273.npy\n",
            "save cache to wmt16/.cache/de2en_val_273.npy\n"
          ]
        }
      ],
      "source": [
        "from pathlib import Path\n",
        "from torch.utils.data import Dataset, DataLoader\n",
        "\n",
        "\n",
        "\n",
        "class LangPairDataset(Dataset):\n",
        "    \"\"\"\n",
        "    双语平行语料数据集类，用于机器翻译任务。\n",
        "    \n",
        "    该类实现了PyTorch的Dataset接口，用于加载和处理德语-英语翻译对数据。\n",
        "    主要功能包括：\n",
        "    1. 从文件加载源语言和目标语言句子\n",
        "    2. 过滤掉超过最大长度的句子\n",
        "    3. 支持数据缓存以提高加载效率\n",
        "    4. 提供标准的数据集访问接口\n",
        "    \n",
        "    数据处理流程：\n",
        "    - 首先检查缓存是否存在且有效\n",
        "    - 如果需要，从原始BPE文件加载数据\n",
        "    - 过滤掉超长句子\n",
        "    - 保存处理后的数据到缓存\n",
        "    - 提供数据访问接口\n",
        "    \"\"\"\n",
        "\n",
        "    def __init__(\n",
        "        self, mode=\"train\", max_length=273, overwrite_cache=False, data_dir=\"wmt16\",\n",
        "    ):\n",
        "        self.data_dir = Path(data_dir) #封装为path对象\n",
        "        cache_path = self.data_dir / \".cache\" / f\"de2en_{mode}_{max_length}.npy\" # 缓存路径\n",
        "\n",
        "        if overwrite_cache or not cache_path.exists(): #判断是否需要覆盖缓存，或者缓存文件不存在\n",
        "            cache_path.parent.mkdir(parents=True, exist_ok=True) # 创建缓存目录\n",
        "\n",
        "            with open(self.data_dir / f\"{mode}_src.bpe\", \"r\", encoding=\"utf8\") as file:\n",
        "                self.src = file.readlines() # 读取源语言文件所有行\n",
        "\n",
        "            with open(self.data_dir / f\"{mode}_trg.bpe\", \"r\", encoding=\"utf8\") as file:\n",
        "                self.trg = file.readlines() # 读取目标语言文件所有行\n",
        "\n",
        "            filtered_src = []\n",
        "            filtered_trg = []\n",
        "            # max length filter,超出最大长度的句子舍弃\n",
        "            for src, trg in zip(self.src, self.trg):\n",
        "                if len(src) <= max_length and len(trg) <= max_length: # 过滤长度超过最大长度的句子\n",
        "                    filtered_src.append(src.strip()) # 去掉句子前后的空格\n",
        "                    filtered_trg.append(trg.strip())\n",
        "            filtered_src = np.array(filtered_src)\n",
        "            filtered_trg = np.array(filtered_trg)\n",
        "            np.save(\n",
        "                cache_path,\n",
        "                {\"src\": filtered_src, \"trg\": filtered_trg },\n",
        "                allow_pickle=True,\n",
        "            )#allow_pickle=True允许保存对象数组，将过滤后的数据保存为 NumPy 数组，存储在缓存文件中\n",
        "            print(f\"save cache to {cache_path}\")\n",
        "\n",
        "        else:\n",
        "            cache_dict = np.load(cache_path, allow_pickle=True).item() #allow_pickle=True允许保存对象数组\n",
        "            print(f\"load {mode} dataset from {cache_path}\")\n",
        "            filtered_src = cache_dict[\"src\"]\n",
        "            filtered_trg = cache_dict[\"trg\"]\n",
        "\n",
        "        self.src = filtered_src\n",
        "        self.trg = filtered_trg\n",
        "\n",
        "    def __getitem__(self, index):\n",
        "        return self.src[index], self.trg[index]\n",
        "\n",
        "    def __len__(self):\n",
        "        return len(self.src)\n",
        "\n",
        "\n",
        "train_ds = LangPairDataset(\"train\")\n",
        "val_ds = LangPairDataset(\"val\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 14,
      "id": "10296400",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "10296400",
        "outputId": "f04344c6-e6f3-45ad-a017-06dc6741faf5"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "29000"
            ]
          },
          "execution_count": 14,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "len(train_ds)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "860a6365",
      "metadata": {
        "id": "860a6365"
      },
      "source": [
        "# Vocab词典"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 15,
      "id": "7e42d55f",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 68,
          "referenced_widgets": [
            "8271841f536f476fa7f168285169b8b0",
            "d04403d6d9de45229ab199c84d8e78b1",
            "83516e53d8044b5984c31b0cfa983454",
            "4111b8dea92d4c73a0d797c900d1c4e4",
            "110a1f620812433692b0442ba588013c",
            "a81f6c3bb6a4482b86d028d608b04559",
            "32ab830293104d33b6f584b0ed030aeb",
            "114607d303c64d558617e41975b25270",
            "9aca93d3cde5487c8d83e9007673f227",
            "e78c6667146541fdb695db5690fa4301",
            "17b7154badac4cae83ae11e0bbc8f881"
          ]
        },
        "id": "7e42d55f",
        "outputId": "56ced5ee-1926-4f3f-af5e-567c4918394c"
      },
      "outputs": [
        {
          "data": {
            "application/vnd.jupyter.widget-view+json": {
              "model_id": "8271841f536f476fa7f168285169b8b0",
              "version_major": 2,
              "version_minor": 0
            },
            "text/plain": [
              "  0%|          | 0/18107 [00:00<?, ?it/s]"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "vocab_size: 18111\n"
          ]
        }
      ],
      "source": [
        "#载入词表，看下词表长度，词表就像英语字典,构建word2idx和idx2word\n",
        "word2idx = {\n",
        "    \"[PAD]\": 0,     # 填充 token\n",
        "    \"[BOS]\": 1,     # begin of sentence\n",
        "    \"[UNK]\": 2,     # 未知 token\n",
        "    \"[EOS]\": 3,     # end of sentence\n",
        "}\n",
        "idx2word = {value: key for key, value in word2idx.items()}\n",
        "index = len(idx2word)\n",
        "threshold = 1  # 出现次数低于此的token舍弃\n",
        "\n",
        "with open(\"wmt16/vocab\", \"r\", encoding=\"utf8\") as file:  # 打开词汇表文件进行读取，使用utf8编码\n",
        "    for line in tqdm(file.readlines()):  # 使用tqdm显示进度条，遍历文件的每一行\n",
        "        token, counts = line.strip().split()  # 去除每行两端的空白字符并按空格分割为token和出现次数\n",
        "        if int(counts) >= threshold:  # 判断token的出现次数是否大于或等于阈值\n",
        "            word2idx[token] = index  # 将token添加到word2idx字典，建立token到索引的映射\n",
        "            idx2word[index] = token  # 将token添加到idx2word字典，建立索引到token的映射\n",
        "            index += 1  # 索引值增加1，为下一个token准备\n",
        "\n",
        "vocab_size = len(word2idx)  # 计算词表大小，即word2idx字典中的条目数量\n",
        "print(\"vocab_size: {}\".format(vocab_size))  # 打印词表大小\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "9e77c79c",
      "metadata": {
        "id": "9e77c79c"
      },
      "source": [
        "# Tokenizer"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 16,
      "id": "656066ff",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "656066ff",
        "outputId": "6f6b6771-6a1a-4d02-9ba1-0f085f7550c8"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "raw text\n",
            "['hello', 'world']\n",
            "['a', 'little', 'boy', 'playing', 'gam@@', 'e@@', 'cu@@', 'be', 'at', 'a', 'mcdonald', '&apos;s', '.']\n",
            "['this', 'is', 'a', 'test']\n",
            "indices\n",
            "tensor([   1, 9458, 3522,    3,    0,    0,    0,    0,    0,    0,    0,    0,\n",
            "           0,    0,    0])\n",
            "tensor([   1,    5,  105,   56,   63, 8664,  732, 2716,  414,   35,    5, 4016,\n",
            "         192,    4,    3])\n",
            "tensor([   1,  385,   18,    5, 5699,    3,    0,    0,    0,    0,    0,    0,\n",
            "           0,    0,    0])\n",
            "decode text\n",
            "[BOS] hello world [EOS] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD]\n",
            "[BOS] a little boy playing gam@@ e@@ cu@@ be at a mcdonald &apos;s . [EOS]\n",
            "[BOS] this is a test [EOS] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD]\n"
          ]
        }
      ],
      "source": [
        "class Tokenizer:\n",
        "    def __init__(self, word2idx, idx2word, max_length=128, pad_idx=0, bos_idx=1, eos_idx=3, unk_idx=2):\n",
        "        self.word2idx = word2idx\n",
        "        self.idx2word = idx2word\n",
        "        self.max_length = max_length\n",
        "        self.pad_idx = pad_idx\n",
        "        self.bos_idx = bos_idx\n",
        "        self.eos_idx = eos_idx\n",
        "        self.unk_idx = unk_idx\n",
        "\n",
        "    def encode(self, text_list, padding_first=False, add_bos=True, add_eos=True, return_mask=False):\n",
        "        \"\"\"如果padding_first == True，则padding加载前面，否则加载后面\"\"\"\n",
        "        max_length = min(self.max_length, add_eos + add_bos + max([len(text) for text in text_list]))\n",
        "        indices_list = []\n",
        "        #text_list是句子列表，每个句子是一个单词列表,text_list是一个批次\n",
        "        for text in text_list:\n",
        "            indices = [self.word2idx.get(word, self.unk_idx) for word in text[:max_length - add_bos - add_eos]]\n",
        "            if add_bos:#如果add_bos == True，则添加[BOS]\n",
        "                indices = [self.bos_idx] + indices\n",
        "            if add_eos:#如果add_eos == True，则添加[EOS]\n",
        "                indices = indices + [self.eos_idx]\n",
        "            if padding_first:#如果padding_first == True，则padding加载前面，否则加载后面\n",
        "                indices = [self.pad_idx] * (max_length - len(indices)) + indices\n",
        "            else:\n",
        "                indices = indices + [self.pad_idx] * (max_length - len(indices))\n",
        "            indices_list.append(indices)\n",
        "        input_ids = torch.tensor(indices_list)\n",
        "        masks = (input_ids == self.pad_idx).to(dtype=torch.int64) # 为了方便损失计算，这里的mask为0的地方需要计算，为1的地方不需要计算\n",
        "        return input_ids if not return_mask else (input_ids, masks)\n",
        "\n",
        "\n",
        "    def decode(self, indices_list, remove_bos=True, remove_eos=True, remove_pad=True, split=False):\n",
        "        text_list = []\n",
        "        for indices in indices_list:\n",
        "            text = []\n",
        "            for index in indices:\n",
        "                word = self.idx2word.get(index, \"[UNK]\")\n",
        "                if remove_bos and word == \"[BOS]\":\n",
        "                    continue\n",
        "                if remove_eos and word == \"[EOS]\":\n",
        "                    break\n",
        "                if remove_pad and word == \"[PAD]\":\n",
        "                    break\n",
        "                text.append(word)\n",
        "            text_list.append(\" \".join(text) if not split else text) #如果split == True，则返回一个单词列表，否则返回一个句子\n",
        "        return text_list #返回一个句子列表\n",
        "\n",
        "\n",
        "tokenizer = Tokenizer(word2idx=word2idx, idx2word=idx2word)\n",
        "\n",
        "\n",
        "raw_text = [\"hello world\".split(), \"a little boy playing gam@@ e@@ cu@@ be at a mcdonald &apos;s .\".split(), \"this is a test\".split()]\n",
        "indices = tokenizer.encode(raw_text, padding_first=False, add_bos=True, add_eos=True)\n",
        "decode_text = tokenizer.decode(indices.tolist(), remove_bos=False, remove_eos=False, remove_pad=False)\n",
        "print(\"raw text\")\n",
        "for raw in raw_text:\n",
        "    print(raw)\n",
        "print(\"indices\")\n",
        "for index in indices:\n",
        "    print(index)\n",
        "print(\"decode text\")\n",
        "for decode in decode_text:\n",
        "    print(decode)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 17,
      "id": "8ef05ff7",
      "metadata": {
        "id": "8ef05ff7"
      },
      "outputs": [],
      "source": [
        "class SampleInfo: #下面的info对象\n",
        "    def __init__(self, i, lens):\n",
        "        \"\"\"\n",
        "        记录文本对的序号和长度信息\n",
        "        输入：\n",
        "            - i (int): 文本对的序号。\n",
        "            - lens (list): 文本对源语言和目标语言的长度\n",
        "        \"\"\"\n",
        "        self.i = i\n",
        "        # 加一是考虑填补在文本前后的特殊词元，lens[0]和lens[1]分别表示源语言和目标语言的长度\n",
        "        self.max_len = max(lens[0], lens[1]) + 1\n",
        "        # self.max_len = lens[0] + 1\n",
        "        self.src_len = lens[0] + 1\n",
        "        self.trg_len = lens[1] + 1\n",
        "\n",
        "# 一个批量生成器，根据词元数目的限制来控制批量的大小。它会根据传入的样本信息，在不超过设定大小的情况下，逐步构建批量。\n",
        "#就是箱子\n",
        "class TokenBatchCreator:\n",
        "    def __init__(self, batch_size):\n",
        "        \"\"\"\n",
        "        参数:\n",
        "        batch_size (int): 用于限制批量的大小。箱子大小 高*宽\n",
        "        功能:\n",
        "        初始化了一个空的批量列表 _batch。\n",
        "        设定了初始的最大长度为 -1。\n",
        "        存储了传入的 batch_size。\n",
        "        \"\"\"\n",
        "\n",
        "        self.__batch = []  #这个就是之前的batch_size，就是第一个batch内有多少个样本\n",
        "        self.max_len = -1  #箱子内最长的样本长度\n",
        "        self._batch_size = batch_size # 限制批量的大小,假设是4096\n",
        "\n",
        "    def append(self, info: SampleInfo):\n",
        "        \"\"\"\n",
        "        参数:\n",
        "        info (SampleInfo): 文本对的信息。\n",
        "        功能:\n",
        "        接收一个 SampleInfo 对象，并根据其最大长度信息更新当前批量的最大长度。\n",
        "        如果将新的样本加入批量后超过了批量大小限制，它会返回已有的批量并将新的样本加入新的批量。\n",
        "        否则，它会更新最大长度并将样本添加到当前批量中。\n",
        "        \"\"\"\n",
        "        # 更新当前批量的最大长度\n",
        "        cur_len = info.max_len # 当前样本的长度\n",
        "        max_len = max(self.max_len, cur_len) # 每来一个样本，更新当前批次的最大长度\n",
        "        # 如果新的样本加入批量后超过大小限制，则将已有的批量返回，新的样本加入新的批量\n",
        "        if max_len * (len(self.__batch) + 1) > self._batch_size:\n",
        "            self.__batch, result = [], self.__batch # 保存当前的batch，并返回,这里的result是之前的batch,_batch清空\n",
        "            self.__batch.append(info) #箱子里的第一条样本，放入\n",
        "            self.max_len = cur_len #因为是当前batch的第一个样本，所以它的长度就是当前长度\n",
        "            return result\n",
        "        else:\n",
        "            self.max_len = max_len\n",
        "            self.__batch.append(info) # 将样本添加到当前批量中\n",
        "            return None\n",
        "\n",
        "    @property\n",
        "    def batch(self):\n",
        "        return self.__batch"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 18,
      "id": "f2f41c51",
      "metadata": {
        "id": "f2f41c51"
      },
      "outputs": [],
      "source": [
        "# 当一个自定义对象可以iter(自定义对象)时，会自动调用__iter__方法\n",
        "from torch.utils.data import BatchSampler\n",
        "import numpy as np\n",
        "\n",
        "\n",
        "class TransformerBatchSampler(BatchSampler):\n",
        "    def __init__(self,\n",
        "                 dataset,\n",
        "                 batch_size,\n",
        "                 shuffle_batch=False,\n",
        "                 clip_last_batch=False,\n",
        "                 seed=0):\n",
        "        \"\"\"\n",
        "        批量采样器\n",
        "        输入:\n",
        "            - dataset: 数据集\n",
        "            - batch_size: 批量大小\n",
        "            - shuffle_batch: 是否对生成的批量进行洗牌\n",
        "            - clip_last_batch: 是否裁剪最后剩下的数据\n",
        "            - seed: 随机数种子\n",
        "        \"\"\"\n",
        "        self._dataset = dataset #数据集\n",
        "        self._batch_size = batch_size #箱子大小\n",
        "        self._shuffle_batch = shuffle_batch #是否打乱箱子\n",
        "        self._clip_last_batch = clip_last_batch #是否裁剪最后剩下的数据\n",
        "        self._seed = seed #下面3个是为了随机\n",
        "        self._random = np.random\n",
        "        self._random.seed(seed)\n",
        "\n",
        "        self._sample_infos = [] #所有样本信息\n",
        "        # 根据数据集中的每个样本，创建了对应的 SampleInfo 对象，包含了样本的索引和长度信息。\n",
        "        for i, data in enumerate(self._dataset):\n",
        "            lens = [len(data[0]), len(data[1])] #输入和输出的长度计算放到lens中\n",
        "            self._sample_infos.append(SampleInfo(i, lens)) #每个样本信息\n",
        "\n",
        "    def __iter__(self):\n",
        "        \"\"\"\n",
        "        对数据集中的样本进行排序，排序规则是先按源语言长度排序，如果相同则按目标语言长度排序。\n",
        "        使用 TokenBatchCreator 逐步组装批量数据，当满足批量大小时返回一个批量的样本信息。\n",
        "        如果不裁剪最后一个批次的数据且存在剩余样本，则将这些样本组成最后一个批次。\n",
        "        如果需要对批量进行洗牌，则对批次进行洗牌操作。\n",
        "        通过迭代器，抛出每个批量的样本在数据集中的索引。\n",
        "        \"\"\"\n",
        "        # 排序，如果源语言长度相同则按照目标语言的长度排列\n",
        "        infos = sorted(self._sample_infos,\n",
        "                       key=lambda x: (x.src_len, x.trg_len))\n",
        "        # 把样本放入到箱子里，所有装箱后的箱子，每一个箱子都放入batch_infos\n",
        "        batch_infos = [] #放箱子的列表，每个箱子都是一个batch\n",
        "        batch_creator = TokenBatchCreator(self._batch_size) # 批量生成器,上面自定义的类\n",
        "        for info in infos:\n",
        "            batch = batch_creator.append(info)\n",
        "            # 存够一个batch的样本信息后，会把这个batch返回，否则返回为None\n",
        "            if batch is not None:\n",
        "                batch_infos.append(batch)\n",
        "\n",
        "        # 是否抛弃最后批量的文本对\n",
        "        if not self._clip_last_batch and len(batch_creator.batch) != 0:\n",
        "            batch_infos.append(batch_creator.batch) # 最后一个batch\n",
        "\n",
        "        # 打乱batch，打乱的是箱子的顺序\n",
        "        if self._shuffle_batch:\n",
        "            self._random.shuffle(batch_infos)\n",
        "\n",
        "        self.batch_number = len(batch_infos) #箱子数量\n",
        "        # print(self.batch_number) #为了理解\n",
        "\n",
        "        # 抛出一个箱子里所有样本的序号\n",
        "        for batch in batch_infos:\n",
        "            batch_indices = [info.i for info in batch] # 批量的样本在数据集中的索引，第一个batch[0,1,.....82]，第二个batch[83,84,85,86,87]\n",
        "            yield batch_indices\n",
        "\n",
        "    def __len__(self):\n",
        "        \"\"\"\n",
        "        返回批量的数量\n",
        "        \"\"\"\n",
        "        if hasattr(self, \"batch_number\"):\n",
        "            return self.batch_number\n",
        "        # 计算批量的数量,没有用到下面的情况，不用看\n",
        "        batch_number = (len(self._dataset) +\n",
        "                        self._batch_size) // self._batch_size\n",
        "        return batch_number"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 19,
      "id": "d9fcba5b",
      "metadata": {
        "id": "d9fcba5b"
      },
      "outputs": [],
      "source": [
        "sampler = TransformerBatchSampler(train_ds, batch_size=4096, shuffle_batch=True)\n",
        "\n",
        "#为什么这里每个批量的样本对数目不一样呢？长度*batch_number>4096的时候，就会返回上一个batch，然后新的样本加入新的batch,具体要看TokenBatchCreator的44行"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 20,
      "id": "5e7a5d82",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "5e7a5d82",
        "outputId": "0a897fa9-68e5-4d61-d605-a89560a8f44b"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "第0批量的数据中含有文本对是：[9107, 10753, 16443, 26511, 23197, 27561, 2289, 28887, 25321, 8029, 1921, 27881, 804, 12064, 4937, 10825, 20403, 21794, 1011, 11803, 2743, 11033, 21357, 6787, 27264, 24877, 28554, 28675, 3377, 720, 7005]，数量为：31\n",
            "第1批量的数据中含有文本对是：[5251, 13027, 19187, 26133, 28219, 1603, 6469, 12633, 4423, 17585, 17839, 26877, 1837, 12925, 24569, 26581, 28167, 7385, 10885, 23498, 18862, 23462, 27539, 28513, 533, 22235, 2703, 2989, 20677, 24901, 25655, 1631, 2787, 6371, 27971, 3739, 4581, 16081, 19849]，数量为：39\n",
            "第2批量的数据中含有文本对是：[26411, 10977, 22298, 2891, 15917, 8851, 9821, 24257, 12999, 10377, 18307, 2565, 26629, 28413, 12829, 3867, 10870, 4304, 17287, 16943, 20464, 21188, 24115, 14887, 17821, 20591, 2646, 6597, 9033, 25028, 27781, 16803]，数量为：32\n",
            "第3批量的数据中含有文本对是：[14339, 20611, 21119, 21529, 21787, 23915, 24563, 24662, 27601, 2091, 2613, 2925, 3041, 3343, 4832, 6515, 13400, 16301, 16528, 18399, 21962, 27328, 28576, 3310, 4486, 5364, 7775, 8276, 10173, 10430, 11393, 11875, 13854, 15481, 19081, 19421, 21478, 22769, 24811, 25583, 26565, 26624, 28863, 613, 2382, 3705, 16254, 19004, 19165, 19595, 20885]，数量为：51\n"
          ]
        }
      ],
      "source": [
        "for idx, batch in enumerate(sampler):\n",
        "    print(\"第{}批量的数据中含有文本对是：{}，数量为：{}\".format(idx, batch, len(batch)))\n",
        "    if idx >= 3:\n",
        "        break"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "9a8adf5a",
      "metadata": {
        "id": "9a8adf5a"
      },
      "source": [
        "# DataLoader"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "b1d2c67e",
      "metadata": {
        "id": "b1d2c67e"
      },
      "outputs": [],
      "source": [
        "def collate_fct(batch, tokenizer):\n",
        "    \"\"\"\n",
        "    批处理函数，用于将数据集中的样本转换为模型输入格式。\n",
        "    \n",
        "    处理流程:\n",
        "    1. 将源语言和目标语言文本分词\n",
        "    2. 为编码器准备输入：源语言文本添加BOS和EOS标记，并生成掩码\n",
        "    3. 为解码器准备输入：目标语言文本添加BOS标记（教师强制学习用）\n",
        "    4. 为解码器准备标签：目标语言文本添加EOS标记（作为预测目标），并生成掩码\n",
        "    5. 将所有张量移至指定设备\n",
        "    \n",
        "    返回包含编码器输入、解码器输入和标签的字典，用于Transformer模型训练\n",
        "    \"\"\"\n",
        "    src_words = [pair[0].split() for pair in batch]\n",
        "    trg_words = [pair[1].split() for pair in batch]\n",
        "\n",
        "    # 编码器输入: [BOS] src [EOS] [PAD]\n",
        "    encoder_inputs, encoder_inputs_mask = tokenizer.encode(\n",
        "        src_words, padding_first=False, add_bos=True, add_eos=True, return_mask=True\n",
        "        )\n",
        "\n",
        "    # 解码器输入: [BOS] trg [PAD]\n",
        "    decoder_inputs = tokenizer.encode(\n",
        "        trg_words, padding_first=False, add_bos=True, add_eos=False, return_mask=False,\n",
        "        )\n",
        "\n",
        "    # 解码器标签: trg [EOS] [PAD]\n",
        "    decoder_labels, decoder_labels_mask = tokenizer.encode(\n",
        "        trg_words, padding_first=False, add_bos=False, add_eos=True, return_mask=True\n",
        "        )\n",
        "\n",
        "    return {\n",
        "        \"encoder_inputs\": encoder_inputs.to(device=device),\n",
        "        \"encoder_inputs_mask\": encoder_inputs_mask.to(device=device),\n",
        "        \"decoder_inputs\": decoder_inputs.to(device=device),\n",
        "        \"decoder_labels\": decoder_labels.to(device=device),\n",
        "        \"decoder_labels_mask\": decoder_labels_mask.to(device=device),\n",
        "    }\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 22,
      "id": "17f23bfe",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "17f23bfe",
        "outputId": "95bfb3e2-bc1b-426f-b54e-6f7d347cd008"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "encoder_inputs\n",
            "tensor([[   1,   11,  591,   25,   12,    7,   17,  589,    9, 1757,  196,   27,\n",
            "           67,  852, 2352,    4,    3],\n",
            "        [   1,    7,   17,   13,  488,  157,    9,   24,    7, 1242,   73,   12,\n",
            "          198, 1094,  308,    4,    3],\n",
            "        [   1,   29,   58,   12,   11,   25,   97,   14,    8,  926,   12, 1145,\n",
            "          625,    4,    3,    0,    0]], device='cuda:0')\n",
            "encoder_inputs_mask\n",
            "tensor([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n",
            "        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n",
            "        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1]], device='cuda:0')\n",
            "decoder_inputs\n",
            "tensor([[  1,   5,  38, 331,  91,  19,   5,  16, 462,  32, 950,  10,  66,   4,\n",
            "           0],\n",
            "        [  1,   5,  16,   6,   5,  45, 157, 109,  69, 113, 364, 265,   5, 757,\n",
            "           4],\n",
            "        [  1,  28, 684,  19,   5,  26,  62,  19, 222,   6,   5, 844,   4,   0,\n",
            "           0]], device='cuda:0')\n",
            "decoder_labels\n",
            "tensor([[  5,  38, 331,  91,  19,   5,  16, 462,  32, 950,  10,  66,   4,   3,\n",
            "           0],\n",
            "        [  5,  16,   6,   5,  45, 157, 109,  69, 113, 364, 265,   5, 757,   4,\n",
            "           3],\n",
            "        [ 28, 684,  19,   5,  26,  62,  19, 222,   6,   5, 844,   4,   3,   0,\n",
            "           0]], device='cuda:0')\n",
            "decoder_labels_mask\n",
            "tensor([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],\n",
            "        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n",
            "        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1]], device='cuda:0')\n"
          ]
        }
      ],
      "source": [
        "from functools import partial # 固定collate_fct的tokenizer参数\n",
        "\n",
        "#可以调大batch_size,来看最终的bleu，如果GPU内存不够，可以减小batch_size\n",
        "sampler = TransformerBatchSampler(train_ds, batch_size=256, shuffle_batch=True)\n",
        "# https://pytorch.org/docs/stable/data.html#torch.utils.data.DataLoader\n",
        "sample_dl = DataLoader(train_ds, batch_sampler=sampler, collate_fn=partial(collate_fct, tokenizer=tokenizer)) #partial函数，固定collate_fct的tokenizer参数\n",
        "\n",
        "for batch in sample_dl:#外层是拿每个batch\n",
        "    for key, value in batch.items():#内层是拿每个batch里面是一个字典\n",
        "        print(key)\n",
        "        print(value)\n",
        "    break"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "597b9d2c",
      "metadata": {
        "id": "597b9d2c"
      },
      "source": [
        "# 定义模型\n",
        "- Transformer模型由Embedding、Transformer-Block组成\n",
        "- Embedding包括：\n",
        "    - WordEmbedding\n",
        "    - PositionEmbedding\n",
        "- 多头注意力\n",
        "- Transformer-Block包括：\n",
        "    - Self-Attention\n",
        "    - Cross-Attention\n",
        "    - MLP"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 23,
      "id": "158da269",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "158da269",
        "outputId": "743b3b43-d35a-4144-cd49-2ef9169988fd"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "tensor(0.0100)\n"
          ]
        }
      ],
      "source": [
        "import torch\n",
        "import math\n",
        "\n",
        "def positional_encoding_weights(emb_size):\n",
        "    # 计算底数和指数\n",
        "    base = math.log(10000)\n",
        "    exponent = -5 / emb_size\n",
        "\n",
        "    # 应用指数函数\n",
        "    # 将 base 转换为 tensor，因为 torch.exp 需要 tensor 类型的输入\n",
        "    weight = torch.exp(torch.tensor(base)*exponent)\n",
        "\n",
        "    return weight\n",
        "\n",
        "emb_size = 10  # 举例，可以替换成你需要的大小\n",
        "weight = positional_encoding_weights(emb_size)\n",
        "print(weight)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c7335220",
      "metadata": {
        "id": "c7335220"
      },
      "source": [
        "## TransformerEmbedding"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 24,
      "id": "bbb0dfb5",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "bbb0dfb5",
        "outputId": "d951c5c8-42f4-4c03-c630-1dfaa8ec8535"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "输入形状: torch.Size([2, 10])\n",
            "输出形状: torch.Size([2, 10, 128])\n"
          ]
        }
      ],
      "source": [
        "import torch\n",
        "import torch.nn as nn\n",
        "import math\n",
        "\n",
        "class TransformerEmbedding(nn.Module):\n",
        "    def __init__(self, config):\n",
        "        super().__init__()\n",
        "        self.vocab_size = config[\"vocab_size\"]\n",
        "        self.hidden_size = config[\"d_model\"]  # 词向量维度\n",
        "        self.pad_idx = config[\"pad_idx\"]\n",
        "        self.max_length = config[\"max_length\"] # 最大token长度\n",
        "        dropout_rate = config[\"dropout\"]  # 随机失活率\n",
        "\n",
        "        # 词嵌入层\n",
        "        self.word_embedding = nn.Embedding(\n",
        "            num_embeddings=self.vocab_size,\n",
        "            embedding_dim=self.hidden_size,\n",
        "            padding_idx=self.pad_idx\n",
        "        )\n",
        "\n",
        "        # 位置编码层 - 不需要训练\n",
        "        self.position_embedding = nn.Embedding(\n",
        "            num_embeddings=self.max_length,\n",
        "            embedding_dim=self.hidden_size\n",
        "        )\n",
        "\n",
        "        # 初始化位置编码，固定不训练\n",
        "        self.register_buffer(\n",
        "            \"position_ids\", torch.arange(self.max_length).expand((1, -1))\n",
        "        )\n",
        "        self.position_embedding.weight.requires_grad = False # 位置编码不需要训练\n",
        "        self._init_position_encoding() # 初始化位置编码\n",
        "\n",
        "        self.dropout = nn.Dropout(dropout_rate)\n",
        "\n",
        "    def _init_position_encoding(self):\n",
        "        \"\"\"初始化位置编码权重\"\"\"\n",
        "        position = torch.arange(self.max_length).unsqueeze(1)\n",
        "        div_term = torch.exp(torch.arange(0, self.hidden_size, 2) * (-math.log(10000.0) / self.hidden_size))\n",
        "\n",
        "        position_encoding = torch.zeros(self.max_length, self.hidden_size)\n",
        "        position_encoding[:, 0::2] = torch.sin(position * div_term)\n",
        "        position_encoding[:, 1::2] = torch.cos(position * div_term)\n",
        "\n",
        "        self.position_embedding.weight.data.copy_(position_encoding)\n",
        "\n",
        "    def forward(self, x):\n",
        "        seq_length = x.size(1)\n",
        "\n",
        "        # 词嵌入\n",
        "        word_embeddings = self.word_embedding(x)\n",
        "\n",
        "        # 位置编码\n",
        "        position_ids = self.position_ids[:, :seq_length]\n",
        "        position_embeddings = self.position_embedding(position_ids)\n",
        "\n",
        "        # 词嵌入 + 位置编码\n",
        "        embeddings = word_embeddings + position_embeddings\n",
        "\n",
        "        # 应用dropout\n",
        "        embeddings = self.dropout(embeddings)\n",
        "\n",
        "        return embeddings\n",
        "# %% cell 23 code\n",
        "\n",
        "# 初始化TransformerEmbedding并进行前向计算\n",
        "config = {\n",
        "    'vocab_size': 30000,\n",
        "    'd_model': 128,\n",
        "    'max_length': 64,\n",
        "    'pad_idx': 0,\n",
        "    'dropout': 0.1,\n",
        "}\n",
        "\n",
        "# 创建模型实例\n",
        "embedding_model = TransformerEmbedding(config=config)\n",
        "\n",
        "# 创建一个示例输入 (batch_size=2, seq_length=10)\n",
        "sample_input = torch.randint(0, config['vocab_size'], (2, 10))\n",
        "print(f\"输入形状: {sample_input.shape}\")\n",
        "\n",
        "# 前向计算\n",
        "output = embedding_model(sample_input)\n",
        "print(f\"输出形状: {output.shape}\")\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 25,
      "id": "4e625af9",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 455
        },
        "id": "4e625af9",
        "outputId": "d7b1f664-1af9-4773-9812-eb71bb6191bc"
      },
      "outputs": [
        {
          "data": {
            "image/png": "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dVISv4Z43aR2NNrJyxtvvIGsrCxMmzYN69atQ48ePTB48OCTdvdryKxatQoTJkzA6tWrsWzZMlRUVOCiiy5CcXGxqjN58mS8//77ePPNN7Fq1Srs2bMHV111VRBHXbd88803eOGFF9C9e3dTeWO87sOHD+Pcc8+Fw+HAxx9/jJ9//hn//Oc/ERcXp+pUJyV9Q+PRRx/F888/j2effRYbN27Eo48+isceewzPPPOMqtMYrru4uBg9evTA3LlzfR6vzjWOHDkSGzZswLJly/DBBx/giy++wPjx48/UJQREVdddUlKCdevW4YEHHsC6devw9ttvY9OmTbj88stN9RridZNaUqNMSA2Ifv36GRMmTFA/ezweIzU11Zg1a1YQR3V62bdvnwHAWLVqlWEYhpGfn284HA7jzTffVHU2btxoADCys7ODNcw648iRI0b79u2NZcuWGX/84x+NO+64wzCMxnvd9957rzFgwAC/x71er5GcnGw8/vjjqiw/P99wuVzGv//97zMxxNPC0KFDjb/85S+msquuusoYOXKkYRiN87oBGO+88476uTrX+PPPPxsAjG+++UbV+fjjjw2LxWLs3r37jI29Npx43b5Yu3atAcDYsWOHYRiN47pJzWmUKy/l5eXIyckxpea2Wq3IzMxEdnZ2EEd2ejm+WVB8fDwAICcnBxUVFab70KlTJ7Rs2bJR3IcJEyZg6NChpusDGu91v/fee+jbty+uvvpqNG3aFL169cJLL72kjp8qJX1DpX///li+fDl+/fVXAMD333+PL7/8EhdffDGAxnvdOtW5xuzsbMTGxqJv376qTmZmJqxWK9asWXPGx3y6KCgogMViQWxsLIDQuW5ipt7vsBsIBw4cgMfjOWkX3qSkJPzyyy9BGtXpxev1YtKkSTj33HPRtWtXAEBubi6cTqf6JT9OUlIScnNzgzDKumPx4sVYt24dvvnmm5OONdbr/u233/D8888jKysLf/vb3/DNN9/g9ttvh9PpxOjRo9W1+frcN+Trvu+++1BYWIhOnTrBZrPB4/HgoYcewsiRIwGg0V63TnWuMTc3F02bNjUdt9vtiI+PbzT3obS0FPfeey+uu+46lZgxFK6bnEyjnLyEIhMmTMBPP/2EL7/8MthDOe3s2rULd9xxB5YtW3bGs7IGE6/Xi759++Lhhx8GcGy77p9++gnz5s3D6NGjgzy608d//vMfvP7661i0aBHOOussrF+/HpMmTUJqamqjvm5ipqKiAtdccw0Mw8Dzzz8f7OGQINMoHxs1adIENpvtJHdJXl5ejdNuNwQmTpyIDz74AJ9//jmaN2+uypOTk1FeXo78/HxT/YZ+H3JycrBv3z707t0bdrsddrsdq1atwpw5c2C325GUlNQorzslJQVdunQxlXXu3Bk7d+4EYE5Jr9PQr/vuu+/GfffdhxEjRqBbt27485//jMmTJ2PWrFkAGu9161TnGpOTk08yJFRWVuLQoUMN/j4cn7js2LEDy5YtU6suQOO+buKfRjl5cTqd6NOnD5YvX67KvF4vli9fjoyMjCCOrG4xDAMTJ07EO++8gxUrVqB169am43369IHD4TDdh02bNmHnzp0N+j4MGjQIP/74o8pyun79evTt2xcjR45UujFe97nnnnuSFf7XX39Fq1atAJhT0h/neEr6hnzdJSUlsFrNf6psNhu8Xi+AxnvdOtW5xoyMDOTn5yMnJ0fVWbFiBbxeL9LT08/4mOuK4xOXzZs347PPPkNCQoLpeGO9bnIKgh0xfLpYvHix4XK5jFdeecX4+eefjfHjxxuxsbFGbm5usIdWZ9xyyy1GTEyMsXLlSmPv3r3qVVJSourcfPPNRsuWLY0VK1YY3377rZGRkWFkZGQEcdSnB91tZBiN87rXrl1r2O1246GHHjI2b95svP7660Z4eLjxr3/9S9V55JFHjNjYWOPdd981fvjhB+OKK64wWrdubRw9ejSII68do0ePNpo1a2Z88MEHxrZt24y3337baNKkiXHPPfeoOo3huo8cOWJ89913xnfffWcAMJ588knju+++U66a6lzjkCFDjF69ehlr1qwxvvzyS6N9+/bGddddF6xLqhZVXXd5eblx+eWXG82bNzfWr19v+jtXVlam+miI101qR6OdvBiGYTzzzDNGy5YtDafTafTr189YvXp1sIdUpwDw+Vq4cKGqc/ToUePWW2814uLijPDwcOPKK6809u7dG7xBnyZOnLw01ut+//33ja5duxoul8vo1KmT8eKLL5qOe71e44EHHjCSkpIMl8tlDBo0yNi0aVOQRls3FBYWGnfccYfRsmVLw+12G23atDH+/ve/m/7zagzX/fnnn/v8fR49erRhGNW7xoMHDxrXXXedERkZaURHRxtjxowxjhw5EoSrqT5VXfe2bdv8/p37/PPPVR8N8bpJ7bAYhrZNJSGEEEJIPadRxrwQQgghpPHCyQshhBBCGhScvBBCCCGkQcHJCyGEEEIaFJy8EEIIIaRBwckLIYQQQhoUnLwQQgghpEHByQshpFps374dFosF69evD/ZQCCEhDicvhDQQbrzxRlgsFlgsFjgcDiQlJeHCCy/EggULVJ6fujzXsGHD6rRPQgipKzh5IaQBMWTIEOzduxfbt2/Hxx9/jAsuuAB33HEHLr30UlRWVgZ7eIQQckbg5IWQBoTL5UJycjKaNWuG3r17429/+xveffddfPzxx3jllVcAAPn5+bjpppuQmJiI6OhoDBw4EN9//73qY/r06ejZsydeeOEFtGjRAuHh4bjmmmtQUFCgjr/66qt499131UrPypUrVfvffvsNF1xwAcLDw9GjRw9kZ2efyVtACCGcvBDS0Bk4cCB69OiBt99+GwBw9dVXY9++ffj444+Rk5OD3r17Y9CgQTh06JBqs2XLFvznP//B+++/j6VLl+K7777DrbfeCgC46667cM0116hVnr1796J///6q7d///nfcddddWL9+PTp06IDrrruOqz6EkDMKJy+ENAI6deqE7du348svv8TatWvx5ptvom/fvmjfvj2eeOIJxMbG4q233lL1S0tL8dprr6Fnz54477zz8Mwzz2Dx4sXIzc1FZGQkwsLC1CpPcnIynE6nanvXXXdh6NCh6NChA2bMmIEdO3Zgy5YtwbhsQkiIwskLIY0AwzBgsVjw/fffo6ioCAkJCYiMjFSvbdu2YevWrap+y5Yt0axZM/VzRkYGvF4vNm3adMpzde/eXemUlBQAwL59++rwagghpGrswR4AIaT2bNy4Ea1bt0ZRURFSUlJMMSrHiY2NrZNzORwOpS0WCwDUuduJEEKqgpMXQho4K1aswI8//ojJkyejefPmyM3Nhd1uR1pamt82O3fuxJ49e5CamgoAWL16NaxWKzp27AgAcDqd8Hg8Z2L4hBBSYzh5IaQBUVZWhtzcXHg8HuTl5WHp0qWYNWsWLr30UowaNQpWqxUZGRkYNmwYHnvsMXTo0AF79uzBhx9+iCuvvBJ9+/YFALjdbowePRpPPPEECgsLcfvtt+Oaa65BcnIyACAtLQ2ffPIJNm3ahISEBMTExATzsgkhxAQnL4Q0IJYuXYqUlBTY7XbExcWhR48emDNnDkaPHg2r9VgI20cffYS///3vGDNmDPbv34/k5GScd955SEpKUv20a9cOV111FS655BIcOnQIl156KZ577jl1fNy4cVi5ciX69u2LoqIifP7551Wu5BBCyJnEYhiGEexBEELOHNOnT8eSJUu4zT8hpMFCtxEhhBBCGhScvBBCCCGkQcHHRoQQQghpUHDlhRBCCCENCk5eCCGEENKg4OSFEEIIIQ0KTl4IIYQQ0qDg5IUQQgghDQpOXgghhBDSoODkhRBCCCENCk5eCCGEENKg4OSFEEIIIQ2K/wcnumZWHU5nbgAAAABJRU5ErkJggg==",
            "text/plain": [
              "<Figure size 640x480 with 2 Axes>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "def plot_position_embedding(position_embedding):# 绘制位置编码\n",
        "    plt.pcolormesh(position_embedding) # 绘制位置编码矩阵\n",
        "    plt.xlabel('Depth')\n",
        "    plt.ylabel('Position')\n",
        "    plt.colorbar() # 颜色条，-1到1的颜色范围\n",
        "    plt.show()\n",
        "\n",
        "# 创建TransformerEmbedding实例并绘制位置编码\n",
        "config = {\n",
        "    'vocab_size': 30000,\n",
        "    'd_model': 128,\n",
        "    'max_length': 64,\n",
        "    'pad_idx':0,\n",
        "    'dropout':0.1,\n",
        "}\n",
        "embedding_model = TransformerEmbedding(config=config)\n",
        "position_embedding_data = embedding_model.position_embedding.weight.data\n",
        "plot_position_embedding(position_embedding_data)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6b85c5f6",
      "metadata": {
        "id": "6b85c5f6"
      },
      "source": [
        "## MultiHeadAttention(缩放点积注意力)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 26,
      "id": "99623244",
      "metadata": {
        "id": "99623244"
      },
      "outputs": [],
      "source": [
        "from dataclasses import dataclass\n",
        "\n",
        "\n",
        "Tensor = torch.Tensor\n",
        "@dataclass\n",
        "class AttentionOutput:\n",
        "    hidden_states: Tensor\n",
        "    attn_scores: Tensor\n",
        "\n",
        "class MultiHeadAttention(nn.Module):\n",
        "    def __init__(self, config):\n",
        "        super().__init__()\n",
        "        self.hidden_size = config[\"d_model\"]  # 隐藏层大小\n",
        "        self.num_heads = config[\"num_heads\"]  # 多头注意力的头数\n",
        "\n",
        "        # 确保hidden_size可以被num_heads整除\n",
        "        assert self.hidden_size % self.num_heads == 0, \"hidden_size must be divisible by num_heads\"\n",
        "\n",
        "        # 每个头的维度,512/8=64\n",
        "        self.depth = self.hidden_size // self.num_heads\n",
        "\n",
        "        # 创建四个线性变换层\n",
        "        self.Wq = nn.Linear(self.hidden_size, self.hidden_size)\n",
        "        self.Wk = nn.Linear(self.hidden_size, self.hidden_size)\n",
        "        self.Wv = nn.Linear(self.hidden_size, self.hidden_size)\n",
        "        self.Wo = nn.Linear(self.hidden_size, self.hidden_size)\n",
        "\n",
        "    def split_heads(self, x, batch_size):\n",
        "        \"\"\"\n",
        "        将输入张量分割成多个头\n",
        "        x shape: (batch_size, seq_len, hidden_size)\n",
        "        返回 shape: (batch_size, num_heads, seq_len, depth)\n",
        "        \"\"\"\n",
        "        # 重塑为 (batch_size, seq_len, num_heads, depth)\n",
        "        x = x.view(batch_size, -1, self.num_heads, self.depth)\n",
        "        # 转置为 (batch_size, num_heads, seq_len, depth)\n",
        "        return x.permute(0, 2, 1, 3)\n",
        "\n",
        "    def merge_heads(self, x, batch_size):\n",
        "        \"\"\"\n",
        "        将多头注意力的输出合并\n",
        "        x shape: (batch_size, num_heads, seq_len, depth)\n",
        "        返回 shape: (batch_size, seq_len, hidden_size)\n",
        "        \"\"\"\n",
        "        # (batch_size, num_heads, seq_len, depth) 转置回 (batch_size, seq_len, num_heads, depth)\n",
        "        x = x.permute(0, 2, 1, 3)\n",
        "        # 重塑为 (batch_size, seq_len, hidden_size)\n",
        "        return x.reshape(batch_size, -1, self.hidden_size)\n",
        "\n",
        "    def scaled_dot_product_attention(self, Q, K, V, mask=None):\n",
        "        \"\"\"\n",
        "        计算缩放点积注意力\n",
        "        Q, K, V shape: (batch_size, num_heads, seq_len, depth)\n",
        "        mask shape: (batch_size, 1, 1, seq_len) 或 (batch_size, 1, seq_len, seq_len)\n",
        "        \"\"\"\n",
        "        # 计算注意力分数\n",
        "        matmul_qk = torch.matmul(Q, K.transpose(-2, -1))  # (batch_size, num_heads, seq_len_q, seq_len_k)\n",
        "\n",
        "        # 缩放\n",
        "        dk = torch.tensor(self.depth, dtype=torch.float32)\n",
        "        scaled_attention_logits = matmul_qk / torch.sqrt(dk)\n",
        "        # print(f'scaled_attention_logits.shape:{scaled_attention_logits.shape}')\n",
        "        # print(f'mask.shape{mask.shape}')\n",
        "        # 应用掩码（如果提供）\n",
        "        if mask is not None:\n",
        "            scaled_attention_logits += (mask * -1e9)\n",
        "\n",
        "        # softmax归一化\n",
        "        attention_weights = F.softmax(scaled_attention_logits, dim=-1)  # (batch_size, num_heads, seq_len_q, seq_len_k)\n",
        "\n",
        "        # 应用注意力权重\n",
        "        #(batch_size, num_heads, seq_len_q, seq_len_k) * (batch_size, num_heads, seq_len_v, depth) = (batch_size, num_heads, seq_len_q, depth)\n",
        "        output = torch.matmul(attention_weights, V)  # (batch_size, num_heads, seq_len_q, depth)\n",
        "\n",
        "        return output, attention_weights\n",
        "\n",
        "    def forward(self, Q, K, V, mask=None):\n",
        "        \"\"\"\n",
        "        入参Q,K,V都是X\n",
        "        \"\"\"\n",
        "        batch_size = Q.shape[0]\n",
        "\n",
        "        # 线性变换\n",
        "        Q = self.Wq(Q)  # (batch_size, seq_len_q, hidden_size)\n",
        "        K = self.Wk(K)  # (batch_size, seq_len_k, hidden_size)\n",
        "        V = self.Wv(V)  # (batch_size, seq_len_v, hidden_size)\n",
        "\n",
        "        # 分割成多头\n",
        "        Q = self.split_heads(Q, batch_size)  # (batch_size, num_heads, seq_len_q, depth)\n",
        "        K = self.split_heads(K, batch_size)  # (batch_size, num_heads, seq_len_k, depth)\n",
        "        V = self.split_heads(V, batch_size)  # (batch_size, num_heads, seq_len_v, depth)\n",
        "\n",
        "        # 计算缩放点积注意力,scaled_attention (batch_size, num_heads, seq_len_q, depth)\n",
        "        # attention_weights (batch_size, num_heads, seq_len_q, seq_len_k)\n",
        "        scaled_attention, attention_weights = self.scaled_dot_product_attention(Q, K, V, mask)\n",
        "\n",
        "        # 合并多头\n",
        "        concat_attention = self.merge_heads(scaled_attention, batch_size)  # (batch_size, seq_len_q, hidden_size)\n",
        "\n",
        "        # 最后的线性层\n",
        "        output = self.Wo(concat_attention)  # (batch_size, seq_len_q, hidden_size)\n",
        "\n",
        "        return AttentionOutput(hidden_states=output, attn_scores=attention_weights)\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 27,
      "id": "970f1a70",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "970f1a70",
        "outputId": "2b90290a-8fa9-4bb5-83db-b7cc780d7722"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "输入张量形状: torch.Size([2, 4, 8])\n",
            "输出张量形状: torch.Size([2, 4, 8])\n",
            "注意力权重形状: torch.Size([2, 2, 4, 4])\n"
          ]
        }
      ],
      "source": [
        "# 验证MultiHeadAttention的正向计算\n",
        "import torch\n",
        "import matplotlib.pyplot as plt\n",
        "\n",
        "# 创建一个简单的测试用例\n",
        "batch_size = 2\n",
        "seq_len = 4\n",
        "hidden_size = 8\n",
        "num_heads = 2\n",
        "\n",
        "# 创建输入张量\n",
        "x = torch.randn(batch_size, seq_len, hidden_size)\n",
        "print(f\"输入张量形状: {x.shape}\")\n",
        "\n",
        "# 创建配置字典\n",
        "config = {\n",
        "    'd_model': hidden_size,\n",
        "    'num_heads': num_heads\n",
        "}\n",
        "\n",
        "# 创建MultiHeadAttention实例\n",
        "mha = MultiHeadAttention(config)\n",
        "\n",
        "# 执行前向传播 (Q=K=V=x，无掩码)\n",
        "output = mha(x, x, x)\n",
        "\n",
        "# 打印结果\n",
        "print(f\"输出张量形状: {output.hidden_states.shape}\")\n",
        "print(f\"注意力权重形状: {output.attn_scores.shape}\")\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "f2f28a04",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "f2f28a04",
        "outputId": "210db89b-2e82-401a-8509-f865dc50c36a"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "查询张量形状: torch.Size([2, 4, 8])\n",
            "键值张量形状: torch.Size([2, 6, 8])\n",
            "输出张量形状: torch.Size([2, 4, 8])\n",
            "注意力权重形状: torch.Size([2, 2, 4, 6])\n"
          ]
        }
      ],
      "source": [
        "# 这段代码测试了多头注意力机制(MultiHeadAttention)的交叉注意力功能\n",
        "# 主要步骤包括:\n",
        "# 1. 创建不同长度的查询张量(q)和键值张量(kv)，模拟交叉注意力场景\n",
        "# 2. 设置模型配置参数(批次大小、序列长度、隐藏维度、注意力头数)\n",
        "# 3. 实例化MultiHeadAttention模型并执行前向计算\n",
        "# 4. 验证输出张量和注意力权重的形状是否符合预期\n",
        "# 这验证了模型能够处理查询序列与键值序列长度不同的情况，即交叉注意力计算\n",
        "import torch  # 导入PyTorch库\n",
        "import matplotlib.pyplot as plt  # 导入matplotlib可视化库\n",
        "\n",
        "# 设置测试参数\n",
        "batch_size = 2  # 批次大小\n",
        "seq_len_q = 4  # 查询序列长度\n",
        "seq_len_kv = 6  # 键值序列长度，与查询不同以测试交叉注意力\n",
        "hidden_size = 8  # 隐藏层维度\n",
        "num_heads = 2  # 注意力头数量\n",
        "\n",
        "# 创建随机输入张量\n",
        "q = torch.randn(batch_size, seq_len_q, hidden_size)  # 创建查询张量\n",
        "kv = torch.randn(batch_size, seq_len_kv, hidden_size)  # 创建键值张量\n",
        "print(f\"查询张量形状: {q.shape}\")  # 打印查询张量形状\n",
        "print(f\"键值张量形状: {kv.shape}\")  # 打印键值张量形状\n",
        "\n",
        "# 创建模型配置\n",
        "config = {\n",
        "    'd_model': hidden_size,  # 设置模型维度\n",
        "    'num_heads': num_heads  # 设置注意力头数\n",
        "}\n",
        "\n",
        "# 实例化并测试模型\n",
        "mha = MultiHeadAttention(config)  # 创建多头注意力实例\n",
        "output = mha(q, kv, kv)  # 执行前向传播，q作为查询，kv作为键和值\n",
        "\n",
        "# 输出结果\n",
        "print(f\"输出张量形状: {output.hidden_states.shape}\")  # 打印输出隐藏状态形状\n",
        "print(f\"注意力权重形状: {output.attn_scores.shape}\")  # 打印注意力权重形状\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "26e43424",
      "metadata": {
        "id": "26e43424"
      },
      "source": [
        "## TransformerBlock"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "66324f21",
      "metadata": {
        "id": "66324f21"
      },
      "outputs": [],
      "source": [
        "from dataclasses import dataclass\n",
        "from typing import Optional\n",
        "\n",
        "@dataclass\n",
        "class TransformerBlockOutput:\n",
        "    \"\"\"存储Transformer块的输出，包括隐藏状态和注意力分数\"\"\"\n",
        "    hidden_states: torch.Tensor  # 输出的隐藏状态\n",
        "    self_attn_scores: torch.Tensor  # 自注意力分数\n",
        "    cross_attn_scores: Optional[torch.Tensor] = None  # 可选的交叉注意力分数\n",
        "\n",
        "class TransformerBlock(nn.Module):\n",
        "    \"\"\"Transformer块实现，包含自注意力机制、可选的交叉注意力和前馈神经网络\n",
        "    \n",
        "    该模块是Transformer架构的核心构建块，用于编码器和解码器中。\n",
        "    每个块包含以下组件：\n",
        "    1. 多头自注意力层\n",
        "    2. 可选的多头交叉注意力层（用于解码器）\n",
        "    3. 前馈神经网络\n",
        "    每个组件后都有残差连接、dropout和层归一化\n",
        "    \"\"\"\n",
        "    def __init__(self, config, has_cross_attention=False):\n",
        "        super().__init__()\n",
        "        self.has_cross_attention = has_cross_attention\n",
        "        self.d_model = config['d_model']\n",
        "        self.ffn_dim = config.get('dim_feedforward', 4 * self.d_model)  # 使用配置中的ffn_dim或默认值\n",
        "\n",
        "        # 为不同组件创建独立的dropout层\n",
        "        self.self_attn_dropout = nn.Dropout(config.get('dropout', 0.1))\n",
        "        self.cross_attn_dropout = nn.Dropout(config.get('dropout', 0.1))\n",
        "        self.ffn_dropout = nn.Dropout(config.get('dropout', 0.1))\n",
        "\n",
        "        # 自注意力层\n",
        "        self.self_attention = MultiHeadAttention(config)\n",
        "        # 层归一化\n",
        "        self.self_attn_layer_norm = nn.LayerNorm(self.d_model)\n",
        "\n",
        "        # 交叉注意力层（可选）\n",
        "        if has_cross_attention:\n",
        "            self.cross_attention = MultiHeadAttention(config)\n",
        "            self.cross_attn_layer_norm = nn.LayerNorm(self.d_model)\n",
        "\n",
        "        # 前馈神经网络\n",
        "        self.ffn = nn.Sequential(\n",
        "            nn.Linear(self.d_model, self.ffn_dim),\n",
        "            nn.ReLU(),\n",
        "            # nn.Dropout(config.get('dropout', 0.1)),  # FFN内部的dropout\n",
        "            nn.Linear(self.ffn_dim, self.d_model)\n",
        "        )\n",
        "        self.ffn_layer_norm = nn.LayerNorm(self.d_model)\n",
        "\n",
        "    def forward(self, x, encoder_output=None, self_attn_mask=None, cross_attn_mask=None):\n",
        "        \"\"\"前向传播过程，依次执行自注意力、交叉注意力（如果有）和前馈网络\"\"\"\n",
        "        # 自注意力层 + dropout + 残差连接 + LayerNorm\n",
        "        self_attn_output = self.self_attention(x, x, x, self_attn_mask)\n",
        "        x = x + self.self_attn_dropout(self_attn_output.hidden_states)  # 使用专用的self_attn_dropout\n",
        "        x = self.self_attn_layer_norm(x)\n",
        "\n",
        "        self_attn_scores = self_attn_output.attn_scores\n",
        "        cross_attn_scores = None\n",
        "\n",
        "        # 交叉注意力层（如果有） + dropout + 残差连接 + LayerNorm\n",
        "        if self.has_cross_attention and encoder_output is not None:\n",
        "            cross_attn_output = self.cross_attention(x, encoder_output, encoder_output, cross_attn_mask)\n",
        "            x = x + self.cross_attn_dropout(cross_attn_output.hidden_states)  # 使用专用的cross_attn_dropout\n",
        "            x = self.cross_attn_layer_norm(x)\n",
        "            cross_attn_scores = cross_attn_output.attn_scores\n",
        "\n",
        "        # 前馈神经网络 + dropout + 残差连接 + LayerNorm\n",
        "        ffn_output = self.ffn(x)\n",
        "        x = x + self.ffn_dropout(ffn_output)  # 使用专用的ffn_dropout\n",
        "        x = self.ffn_layer_norm(x)\n",
        "\n",
        "        return TransformerBlockOutput(\n",
        "            hidden_states=x,\n",
        "            self_attn_scores=self_attn_scores,\n",
        "            cross_attn_scores=cross_attn_scores\n",
        "        )\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "36a5a199",
      "metadata": {
        "id": "36a5a199"
      },
      "source": [
        "## TransformerEncoder"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "081570d2",
      "metadata": {
        "id": "081570d2"
      },
      "outputs": [],
      "source": [
        "# Transformer编码器实现\n",
        "# \n",
        "# 这段代码实现了Transformer模型的编码器部分，主要包含两个组件：\n",
        "# 1. TransformerEncoderOutput：数据类，用于存储编码器的输出结果\n",
        "#    - last_hidden_states：最终的隐藏状态\n",
        "#    - attn_scores：各层的注意力分数列表\n",
        "#\n",
        "# 2. TransformerEncoder：编码器主体类，继承自nn.Module\n",
        "#    - 由多个TransformerBlock堆叠组成\n",
        "#    - 不包含交叉注意力机制\n",
        "#    - 前向传播时依次通过每层编码器，并收集每层的注意力分数\n",
        "#    - 默认包含6个编码器层，可通过配置修改\n",
        "\n",
        "from dataclasses import dataclass\n",
        "from typing import List\n",
        "\n",
        "import torch\n",
        "from torch import Tensor\n",
        "import torch.nn as nn\n",
        "\n",
        "@dataclass\n",
        "class TransformerEncoderOutput:\n",
        "    last_hidden_states: Tensor  # 最终的隐藏状态\n",
        "    attn_scores: List[Tensor]   # 各层的注意力分数列表\n",
        "\n",
        "class TransformerEncoder(nn.Module):\n",
        "    def __init__(self, config):\n",
        "        super().__init__()\n",
        "        self.num_layers = config.get('encoder_layers', 6)  # 编码器层数，默认为6\n",
        "\n",
        "        # 创建多层Transformer编码器块，不包含交叉注意力机制\n",
        "        self.layers = nn.ModuleList([\n",
        "            TransformerBlock(config, has_cross_attention=False)\n",
        "            for _ in range(self.num_layers)\n",
        "        ])\n",
        "\n",
        "    def forward(self, x, attention_mask=None):\n",
        "        all_attn_scores = []  # 存储所有层的注意力分数\n",
        "\n",
        "        # 依次通过每个编码器层\n",
        "        for layer in self.layers:\n",
        "            output = layer(x, self_attn_mask=attention_mask)\n",
        "            x = output.hidden_states\n",
        "            all_attn_scores.append(output.self_attn_scores)\n",
        "\n",
        "        return TransformerEncoderOutput(\n",
        "            last_hidden_states=x,\n",
        "            attn_scores=all_attn_scores\n",
        "        )\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 31,
      "id": "abe12b93",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "abe12b93",
        "outputId": "448a71dc-060b-4d71-d50d-5bf4ab5ae8aa"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "tensor([[[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]],\n",
            "\n",
            "\n",
            "        [[[0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1]]]])\n",
            "输出张量形状: torch.Size([2, 12, 64])\n",
            "注意力层数: 2\n",
            "第一层注意力分数形状: torch.Size([2, 4, 12, 12])\n",
            "第一层第二个样本的注意力分数，第9个位置是否接近0: False\n"
          ]
        }
      ],
      "source": [
        "def test_transformer_encoder():\n",
        "    # 创建一个简单的配置\n",
        "    config = {\n",
        "        'encoder_layers': 2,\n",
        "        'd_model': 64,\n",
        "        'num_heads': 4,\n",
        "        'dim_feedforward': 128,\n",
        "        'dropout': 0.1,\n",
        "        'max_length': 100,\n",
        "        'vocab_size': vocab_size,\n",
        "        'pad_idx': 0,\n",
        "    }\n",
        "\n",
        "    # 实例化模型\n",
        "    encoder = TransformerEncoder(config)\n",
        "\n",
        "    # 生成一个批次的输入\n",
        "    batch_size = 2\n",
        "    hidden_size = config['d_model']\n",
        "\n",
        "    inputs_words = [\"The quick brown fox jumps over the lazy dog .\", \"What does the fox say ?\"]\n",
        "\n",
        "    #encode变为id\n",
        "    # 使用tokenizer将文本编码为token IDs\n",
        "    src_sequence, src_padding_mask = tokenizer.encode([w.split() for w in inputs_words], return_mask=True)\n",
        "    # 通过TransformerEmbedding处理输入序列\n",
        "    src_embedded = TransformerEmbedding(config)(src_sequence)\n",
        "    print(src_padding_mask.unsqueeze(1).unsqueeze(2))\n",
        "\n",
        "    # 执行前向传播\n",
        "    output = encoder(src_embedded, src_padding_mask.unsqueeze(1).unsqueeze(2))\n",
        "\n",
        "    # 验证输出形状\n",
        "    print(f\"输出张量形状: {output.last_hidden_states.shape}\")\n",
        "    print(f\"注意力层数: {len(output.attn_scores)}\")\n",
        "    print(f\"第一层注意力分数形状: {output.attn_scores[0].shape}\")\n",
        "\n",
        "    # 检查注意力掩码是否正常工作\n",
        "    # 对于被掩盖的位置，注意力分数应该很小\n",
        "    print(f\"第一层第二个样本的注意力分数，第9个位置是否接近0: {output.attn_scores[0][1, :, 8:].mean().item() < 0.01}\")\n",
        "\n",
        "    return output\n",
        "\n",
        "# 运行测试\n",
        "test_output = test_transformer_encoder()\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "97a1b24f",
      "metadata": {
        "id": "97a1b24f"
      },
      "source": [
        "## TransformerDecoder"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "eebcf9f5",
      "metadata": {
        "id": "eebcf9f5"
      },
      "outputs": [],
      "source": [
        "from dataclasses import dataclass\n",
        "from typing import List\n",
        "\n",
        "# 定义TransformerDecoder的输出数据结构\n",
        "@dataclass\n",
        "class TransformerDecoderOutput:\n",
        "    last_hidden_states: torch.Tensor  # 最终的隐藏状态输出\n",
        "    self_attn_scores: List[torch.Tensor]  # 每一层的自注意力分数列表\n",
        "    cross_attn_scores: List[torch.Tensor]  # 每一层的交叉注意力分数列表\n",
        "\n",
        "# Transformer解码器类\n",
        "class TransformerDecoder(nn.Module):\n",
        "    def __init__(self, config):\n",
        "        super().__init__()\n",
        "        # 创建多层TransformerBlock，每个Block都启用交叉注意力机制\n",
        "        self.layers = nn.ModuleList([\n",
        "            TransformerBlock(\n",
        "                config,\n",
        "                has_cross_attention=True  # 解码器需要交叉注意力来关注编码器的输出\n",
        "            )\n",
        "            for _ in range(config['num_decoder_layers'])  # 根据配置创建指定数量的层\n",
        "        ])\n",
        "        self.dropout = nn.Dropout(config['dropout'])  # 创建dropout层防止过拟合\n",
        "\n",
        "    def forward(self, x, encoder_output, self_attn_mask=None, cross_attn_mask=None):\n",
        "        self_attn_scores = []  # 存储每个层的自注意力分数\n",
        "        cross_attn_scores = []  # 存储每个层的交叉注意力分数\n",
        "\n",
        "        # 依次通过每一层TransformerBlock\n",
        "        for layer in self.layers:\n",
        "            # 将输入、编码器输出和两种注意力掩码传递给当前层\n",
        "            layer_output = layer(\n",
        "                x,                # 当前层的输入\n",
        "                encoder_output,   # 编码器的输出\n",
        "                self_attn_mask,   # 自注意力掩码(通常是look-ahead掩码)\n",
        "                cross_attn_mask   # 交叉注意力掩码(通常是padding掩码)\n",
        "            )\n",
        "\n",
        "            # 更新当前隐藏状态，作为下一层的输入\n",
        "            x = layer_output.hidden_states\n",
        "            # 收集注意力分数用于可视化或分析\n",
        "            self_attn_scores.append(layer_output.self_attn_scores)\n",
        "            cross_attn_scores.append(layer_output.cross_attn_scores)\n",
        "\n",
        "        # 返回最终的输出结果，包含最终隐藏状态和所有层的注意力分数\n",
        "        return TransformerDecoderOutput(\n",
        "            last_hidden_states=x,\n",
        "            self_attn_scores=self_attn_scores,\n",
        "            cross_attn_scores=cross_attn_scores\n",
        "        )\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e1e476f2",
      "metadata": {
        "id": "e1e476f2"
      },
      "source": [
        "## 生成look ahead mask"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 33,
      "id": "8254102c",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "8254102c",
        "outputId": "961d2c77-2d52-4ead-de5f-7fa840bc8346"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "tensor([[False,  True,  True,  True,  True],\n",
              "        [False, False,  True,  True,  True],\n",
              "        [False, False, False,  True,  True],\n",
              "        [False, False, False, False,  True],\n",
              "        [False, False, False, False, False]])"
            ]
          },
          "execution_count": 33,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "(torch.triu(torch.ones(5, 5))==0).transpose(-1, -2)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 34,
      "id": "1db53d89",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 634
        },
        "id": "1db53d89",
        "outputId": "760aae68-547a-4053-ce55-67cb32170e4b"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Look-ahead mask for size 3:\n",
            "tensor([[False,  True,  True],\n",
            "        [False, False,  True],\n",
            "        [False, False, False]])\n",
            "\n",
            "Look-ahead mask for size 5:\n",
            "tensor([[False,  True,  True,  True,  True],\n",
            "        [False, False,  True,  True,  True],\n",
            "        [False, False, False,  True,  True],\n",
            "        [False, False, False, False,  True],\n",
            "        [False, False, False, False, False]])\n"
          ]
        },
        {
          "data": {
            "image/png": "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",
            "text/plain": [
              "<Figure size 480x480 with 2 Axes>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "def generate_look_ahead_mask(size):\n",
        "    \"\"\"\n",
        "    生成上三角掩码(look-ahead mask)，用于Transformer解码器中的自注意力机制\n",
        "\n",
        "    Args:\n",
        "        size (int): 掩码的大小 (size x size)\n",
        "\n",
        "    Returns:\n",
        "        torch.Tensor: 布尔类型的上三角掩码，其中True表示被掩盖的位置\n",
        "    \"\"\"\n",
        "    # 创建上三角矩阵(1s在上三角，包括对角线；0s在下三角)\n",
        "    mask = torch.triu(torch.ones(size, size), diagonal=1).bool()\n",
        "\n",
        "    # 在解码器的自注意力中，我们通常掩盖未来的位置(右上方)\n",
        "    # 所以需要转置使得右上方为True(被掩盖)\n",
        "    return mask\n",
        "\n",
        "# 测试不同大小的look-ahead mask\n",
        "print(\"Look-ahead mask for size 3:\")\n",
        "print(generate_look_ahead_mask(3))\n",
        "print(\"\\nLook-ahead mask for size 5:\")\n",
        "print(generate_look_ahead_mask(5))\n",
        "plt.matshow(generate_look_ahead_mask(16))\n",
        "plt.colorbar()\n",
        "plt.xlabel(\"keys\")\n",
        "plt.ylabel(\"querys\")\n",
        "plt.title(\"1 means mask while 0 means unmask\")\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 35,
      "id": "a473db90",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 967
        },
        "id": "a473db90",
        "outputId": "dab9abaf-4e5e-47f6-831a-0107de0e5109"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "['[BOS]', '[UNK]', 'quick', 'brown', '[UNK]', 'jumps', 'over', 'the', '[UNK]', 'dog', '.', '[EOS]']\n"
          ]
        },
        {
          "data": {
            "image/png": "iVBORw0KGgoAAAANSUhEUgAAA1IAAAG1CAYAAADz+MUUAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQAASMZJREFUeJzt3X1cVHX+///ncCEiyECGGkpeYWamqUhayoV5gVSu1q5iZoraupm22mptfmxTu5A1s/pWm+Zamkapu2vZthmkiXhV6iaJpa6GEshaXjKocX1+f/Rz1hFUDsLMAI/77XZuwZkz7/frDM68es45c8ZiGIYhAAAAAEClebi6AAAAAACobQhSAAAAAGASQQoAAAAATCJIAQAAAIBJBCkAAAAAMIkgBQAAAAAmEaQAAAAAwCSCFAAAAACYRJACAAAAAJMIUsBlLFu2TBaLRUeOHHFYP3/+fLVt21aenp7q2rWrS2qrD2bPni2LxaITJ064uhQAKOdyPaK6JCQkyN/fv0bGrsiF/dm1a5fT5ryaC32gtqKP1X0EKcCElJQUPfnkk+rdu7eWLl2quXPnVuv427Zt0+zZs3XmzJlyt82dO1cfffRRtc4HAACAqiFIASZ88cUX8vDw0Ntvv63Ro0fr7rvvrtbxt23bpjlz5hCkAAAA3BxBCjDhp59+kq+vrxo0aODqUgAAAOBCBCnUOfn5+Zo6dapat24tHx8fNW3aVAMGDNDXX39t3+arr77SoEGDZLVa1ahRI0VHR2vr1q1XHNdisWjp0qU6d+6cLBaLLBaLli1bVqma9uzZo4SEBLVt21YNGzZU8+bNNW7cOJ08edK+zezZs/XEE09Iktq0aWOf48iRI7JYLDp37pzeffdd+/qEhAT7/SwWiw4dOqSEhAQFBgbKarVq7NixOn/+vKnH7sI5+T/88IPuvfde+fv7q0WLFvrLX/4iScrIyNBdd90lPz8/tWrVSu+//77D/U+dOqXp06erc+fO8vf3V0BAgOLi4vTNN9+Um+v1119Xp06d1KhRIwUFBalHjx7lxrtUVlaWwsLCdOutt+rHH380tW8AUNPefPNNderUST4+PgoJCdGkSZMqPMPgb3/7m8LDw+Xr66vrr79eo0aN0tGjR686fnp6uoKDgxUTE6OzZ89WqqasrCw9+uij6tChg3x9fdWkSRMNGzbssp/tKiws1B/+8AcFBwfLz89P9913n44fP15uu3Xr1ikyMlJ+fn5q3Lix7rnnHn377bcO21Sm912wZcsWRUREqGHDhmrXrp3eeuutSu3fpehjcCYvVxcAVLdHHnlEf//73zV58mTdcsstOnnypLZs2aJ9+/ape/fu+uKLLxQXF6fw8HDNmjVLHh4eWrp0qe666y5t3rxZt99+e4XjrlixQosXL9aOHTu0ZMkSSdKdd95ZqZo+//xzZWZmauzYsWrevLm+/fZbLV68WN9++62+/PJLWSwW3X///frPf/6jDz74QK+88oquv/56SVJwcLBWrFihhx9+WLfffrsmTJggSWrXrp3DHMOHD1ebNm2UmJior7/+WkuWLFHTpk01b948U49faWmp4uLiFBUVpRdffFFJSUmaPHmy/Pz8NHPmTD344IO6//77tWjRIo0ePVp33HGH2rRpI0nKzMzURx99pGHDhqlNmzb68ccf9dZbbyk6OlrfffedQkJCJEl//etf9fvf/16/+c1vNGXKFBUUFGjPnj366quvNHLkyArr+v7773XXXXfpuuuu0+eff25/fADAHcyePVtz5sxR//79NXHiRB04cEALFy7Uzp07tXXrVnl7e0v65aIOY8eOVUREhBITE/Xjjz/q//2//6etW7dq9+7dCgwMrHD8nTt3KjY2Vj169NDatWvl6+tbqbp27typbdu2acSIEWrZsqWOHDmihQsXKiYmRt99950aNWrksP1jjz2moKAgzZo1S0eOHNGrr76qyZMna9WqVfZtVqxYoTFjxig2Nlbz5s3T+fPntXDhQvXp00e7d+9W69atJVWu90m/hJuBAwcqODhYs2fPVklJiWbNmqVmzZqZ/Cv8gj4GpzGAOsZqtRqTJk2q8LaysjKjffv2RmxsrFFWVmZff/78eaNNmzbGgAED7OuWLl1qSDIOHz5sXzdmzBjDz8/PdE3nz58vt+6DDz4wJBlpaWn2dfPnzy835wV+fn7GmDFjyq2fNWuWIckYN26cw/r77rvPaNKkiak6x4wZY0gy5s6da193+vRpw9fX17BYLMbKlSvt6/fv329IMmbNmmVfV1BQYJSWljqMefjwYcPHx8d49tln7euGDBlidOrU6Yq1XNiv48ePG/v27TNCQkKMiIgI49SpU6b2CQBqwsU94qeffjIaNGhgDBw40OE18I033jAkGe+8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",
            "text/plain": [
              "<Figure size 1000x500 with 2 Axes>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "--------------------------------------------------\n",
            "['[BOS]', '[UNK]', 'does', 'the', '[UNK]', 'say', '?', '[EOS]', '[PAD]', '[PAD]', '[PAD]', '[PAD]']\n"
          ]
        },
        {
          "data": {
            "image/png": "iVBORw0KGgoAAAANSUhEUgAAA1AAAAG1CAYAAAD3DRUpAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAR7tJREFUeJzt3XtcVHX+x/E3iAKCM1jhhSBTM80yLbz9VGTE5NJlKfNuq6ibm9qGpW766OKtJCPTLlvKumkXNzOl2s1IvOElLW1T0U1dy0sgWpoK3kAu5/fHPphlAvGAODPA6/l4zGOZM2e+n89hhXcfzswZD8MwDAEAAAAArsjT1Q0AAAAAQHXBAAUAAAAAJjFAAQAAAIBJDFAAAAAAYBIDFAAAAACYxAAFAAAAACYxQAEAAACASQxQAAAAAGASAxQAAAAAmMQABZRh8eLF8vDw0OHDhx22JyYmqkWLFqpTp446dOjgkt5qg2nTpsnDw0MnT550dSsAUMrlMqKqxMXFyd/f/5qsXZbi4/n222+dVvNKinOguiLHajYGKMCk1NRU/fnPf1b37t21aNEizZo1q0rX37Jli6ZNm6YzZ86UemzWrFn69NNPq7QeAAAAKo4BCjBp3bp18vT01N/+9jcNGzZM9957b5Wuv2XLFk2fPp0BCgAAwI0xQAEm/fLLL/L19VW9evVc3QoAAABchAEKNcrZs2c1fvx43XzzzfL29lajRo3Up08ffffdd/Z9vvnmG0VHR8tqtap+/foKDw/XV199Ve66Hh4eWrRokc6fPy8PDw95eHho8eLFpnpKT09XXFycWrRoIR8fHzVp0kQjR47Ur7/+at9n2rRpmjRpkiSpefPm9hqHDx+Wh4eHzp8/r3fffde+PS4uzv48Dw8P/fDDD4qLi1NAQICsVqtGjBihCxcuVOh7V/ya+59++kn333+//P39deONN+ovf/mLJGn37t2KiIiQn5+fmjVrpr///e8Ozz916pQmTpyodu3ayd/fXxaLRTExMdq1a1epWm+88YZuv/121a9fXw0bNlTHjh1LrfdbR44c0S233KI77rhDP//8c4WODQCutbfeeku33367vL29FRQUpHHjxpX5ioKPP/5YoaGh8vX11Q033KBHHnlER48eveL6O3fuVGBgoGw2m86dO2eqpyNHjmjs2LFq3bq1fH19df3116t///6Xfe9WXl6ennrqKQUGBsrPz08PPfSQTpw4UWq/lJQUhYWFyc/PTw0aNNB9992nf//73w77mMm+Yps3b1anTp3k4+Ojli1basGCBaaO77fIMTiLl6sbAKrSY489puXLl+vxxx9X27Zt9euvv2rz5s3au3ev7r77bq1bt04xMTEKDQ3V1KlT5enpqUWLFikiIkKbNm1S586dy1z3/fffV1JSkrZt26aFCxdKkrp162aqp9WrV+vgwYMaMWKEmjRpon//+99KSkrSv//9b3399dfy8PBQ37599Z///Ecffvih5s6dqxtuuEGSFBgYqPfff19/+MMf1LlzZ40ePVqS1LJlS4caAwYMUPPmzZWQkKDvvvtOCxcuVKNGjTR79uwKff8KCwsVExOjnj176uWXX9aSJUv0+OOPy8/PT88884yGDh2qvn37av78+Ro2bJj+7//+T82bN5ckHTx4UJ9++qn69++v5s2b6+eff9aCBQsUHh6u77//XkFBQZKkv/71r3riiSfUr18/xcfHKzc3V+np6frmm280ZMiQMvv68ccfFRERoeuuu06rV6+2f38AwB1MmzZN06dP1z333KMxY8Zo//79evvtt7V9+3Z99dVXqlu3rqT/XqxhxIgR6tSpkxISEvTzzz/rtdde01dffaUdO3YoICCgzPW3b9+uqKgodezYUZ999pl8fX1N9bV9+3Zt2bJFgwYNUnBwsA4fPqy3335bNptN33//verXr++w/5/+9Cc1bNhQU6dO1eHDhzVv3jw9/vjj+uijj+z7vP/++xo+fLiioqI0e/ZsXbhwQW+//bZ69OihHTt26Oabb5ZkLvuk/w41kZGRCgwM1LRp01RQUKCpU6eqcePGFfx/4b/IMTiFAdQgVqvVGDduXJmPFRUVGa1atTKioqKMoqIi+/YLFy4YzZs3N/r06WPftmjRIkOScejQIfu24cOHG35+fhXu6cKFC6W2ffjhh4YkY+PGjfZtiYmJpWoW8/PzM4YPH15q+9SpUw1JxsiRIx22P/TQQ8b1119foT6HDx9uSDJmzZpl33b69GnD19fX8PDwMJYuXWrfvm/fPkOSMXXqVPu23Nxco7Cw0GHNQ4cOGd7e3saMGTPs22JjY43bb7+93F6Kj+vEiRPG3r17jaCgIKNTp07GqVOnKnRMAHAtlMyIX375xahXr54RGRnp8DvwzTff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PfXBBx/owQcf1IABA/TFF1+U+ustALhKYGCgpkyZounTpys6Olq/+93vtH//fr311lvq1KmTHnnkEUlS3bp1NXv2bI0YMULh4eEaPHiw/TLmN998s5588sky1/f19dXnn3+uiIgIxcTEaMOGDbrjjjtM9Xb//ffr/fffl9VqVdu2bbV161atWbNG119/faWO1WKx6O2339bvf/973X333Ro0aJACAwP1008/aeXKlerevbvefPPNCmXf9OnT9eWXXyosLExjx45VQUGB/TOW0tPTK9VnZZFjMM01F/8Dql5eXp4xadIko3379kaDBg0MPz8/o3379sZbb73lsN+OHTuMvn37Gtdff73h7e1tNGvWzBgwYICxdu1a+z5VeRnzzMxM46GHHjICAgIMq9Vq9O/f38jKyip1+VTDMIyZM2caN954o+Hp6elQf9++fUbPnj0NX19fQ5L9kuYlL5NaUln9X8nlji88PLzMy7U2a9bMuO++++z3c3NzjQkTJhhNmzY1fH19je7duxtbt241wsPDjfDwcPt+CxYsMHr27Gn//rds2dKYNGmSkZ2dbd+nrOO6cOGCER4ebvj7+xtff/216eMCgKpW1u/YN99802jTpo1Rt25do3HjxsaYMWOM06dPl3ruRx99ZNx1112Gt7e3cd111xlDhw41MjMzHfYp6/fxyZMnjbZt2xpNmjQxDhw4YKrP06dPGyNGjDBuuOEGw9/f34iKijL27dtnNGvWzOGjMYqPZ/v27Q7PX79+vSHJWL9+fantUVFRhtVqNXx8fIyWLVsacXFxxrfffmvfpyLZt2HDBiM0NNSoV6+e0aJFC2P+/Pn2HKgIcgzO4mEYFXyXOQAAAADUUrwHCgAAAABM4j1QQCVlZ2fr4sWL5e5T1mVena269AkAMOfcuXNlXgyppMDAwMteuru6IcfgbngJH1BJcXFxevfdd8vdxx1+vKpLnwAAc6ZNm1bq84Z+69ChQ7r55pud09A1Ro7B3TBAAZX0/fffKysrq9x9nPV5U+WpLn0CAMw5ePCgDh48WO4+PXr0cPg8ouqMHIO7YYACAAAAAJO4iAQAAAAAmMQABQAAAAAmMUDBbs+ePYqLi3NqzcOHDys1NVWS1LFjR6fWrq2++eYbde/eXXfffbc++OADV7cDAJflilySyCZXIJtQnTBAlZCWlqaQkBAlJSXJ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",
            "text/plain": [
              "<Figure size 1000x500 with 2 Axes>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "--------------------------------------------------\n"
          ]
        }
      ],
      "source": [
        "inputs_words = [\"The quick brown fox jumps over the lazy dog .\", \"What does the fox say ?\"]\n",
        "\n",
        "#encode变为id\n",
        "inputs_ids, input_padding_mask = tokenizer.encode([w.split() for w in inputs_words], return_mask=True)\n",
        "for i in range(len(inputs_words)):\n",
        "    decode_text = tokenizer.decode(inputs_ids[i: i+1].tolist(), remove_bos=False, remove_eos=False, remove_pad=False, split=True)[0]\n",
        "    print(decode_text)\n",
        "    # print(input_padding_mask[i].reshape(1, -1))\n",
        "    #repeat_interleave作用：将input_padding_mask[i]重复inputs_ids.shape[-1]次，dim=0表示在第0维度上重复\n",
        "    self_attn_mask  = input_padding_mask[i].reshape(1, -1).repeat_interleave(inputs_ids.shape[-1], dim=0)\n",
        "    # print(input_mask[i].reshape(1, -1).repeat_interleave(inputs_ids.shape[-1], dim=0))\n",
        "    look_ahead_mask = generate_look_ahead_mask(inputs_ids.shape[-1])\n",
        "\n",
        "    fig, axs = plt.subplots(1, 2, figsize=(10, 5))\n",
        "    axs[0].matshow(self_attn_mask)\n",
        "    axs[0].set_title(\"self_attn_mask\")\n",
        "    axs[0].set_yticks(range(len(decode_text)), decode_text, fontsize=6)\n",
        "    axs[0].set_ylabel(\"querys\")\n",
        "    axs[0].set_xticks(range(len(decode_text)), decode_text, fontsize=6)\n",
        "    axs[0].set_xlabel(\"keys\")\n",
        "    axs[1].matshow(look_ahead_mask)\n",
        "    axs[1].set_title(\"look_ahead_mask\")\n",
        "    axs[1].set_yticks(range(len(decode_text)), decode_text, fontsize=6)\n",
        "    axs[1].set_ylabel(\"querys\")\n",
        "    axs[1].set_xticks(range(len(decode_text)), decode_text, fontsize=6)\n",
        "    axs[1].set_xlabel(\"keys\")\n",
        "    plt.show()\n",
        "    print('-'*50)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "84f2a6c9",
      "metadata": {
        "id": "84f2a6c9"
      },
      "source": [
        "## TransformerModel"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "59fa00df",
      "metadata": {
        "id": "59fa00df"
      },
      "outputs": [],
      "source": [
        "from dataclasses import dataclass\n",
        "from typing import Optional, List, Dict, Any, Tuple\n",
        "import torch\n",
        "import torch.nn as nn\n",
        "import torch.nn.functional as F\n",
        "import math\n",
        "import numpy as np\n",
        "import time\n",
        "\n",
        "\n",
        "# 这里定义了一个使用dataclass装饰器的TransformerOutput类，用于方便地存储和管理Transformer模型的输出结果，包括logits、注意力权重和预测序列等信息\n",
        "@dataclass # @dataclass装饰器，表示该类是一个数据类，用于存储和描述数据对象，该类中的属性将自动创建对应的数据成员变量\n",
        "class TransformerOutput: \n",
        "    logits: torch.Tensor  # 保存模型输出的logits张量，通常用于后续的softmax或损失计算\n",
        "    encoder_attentions: Optional[List[torch.Tensor]] = None  # 保存编码器每一层的注意力权重\n",
        "    decoder_attentions: Optional[List[torch.Tensor]] = None  # 保存解码器每一层的自注意力权重\n",
        "    cross_attentions: Optional[List[torch.Tensor]] = None   # 保存解码器对编码器的交叉注意力权重\n",
        "    preds: Optional[torch.Tensor] = None  # 保存最终的预测结果（如生成的token序列）\n",
        "\n",
        "\n",
        "class TransformerModel(nn.Module):\n",
        "    def __init__(self, config: Dict[str, Any]): # config是一个字典，包含模型配置参数，如d_model、num_heads、pad_token_id、pad_idx、vocab_size、share_embeddings、max_length、bos_idx、eos_idx等\n",
        "        super().__init__()\n",
        "        self.d_model = config.get(\"d_model\", 512) # 模型中每个隐藏层的维度\n",
        "        self.num_heads = config.get(\"num_heads\", 8) # 多头注意力的头数\n",
        "        self.pad_token_id = config.get(\"pad_token_id\", 0) # 从配置字典config中获取pad_token_id（填充token的ID），如果没有指定则默认为0\n",
        "        self.pad_idx = config.get(\"pad_idx\", 0) # 填充token的索引 \n",
        "        self.vocab_size = config.get(\"vocab_size\") # 词表大小\n",
        "        self.share_embeddings = config.get(\"share_embeddings\", False) # 是否共享embedding层\n",
        "        self.max_length=config['max_length'] # 最大序列长度\n",
        "        self.bos_idx = config[\"bos_idx\"] # 句子开始标志的索引\n",
        "        self.eos_idx = config[\"eos_idx\"] # 句子结束标志的索引\n",
        "\n",
        "        # Embedding layers using TransformerEmbedding\n",
        "        self.src_embedding = TransformerEmbedding(config=config) # 创建源语言的embedding层\n",
        "\n",
        "        # 判断是否共享embeddings，将解码器输出的隐藏状态映射到词表的logits空间\n",
        "        self.tgt_embedding = TransformerEmbedding(config=config)\n",
        "        if self.share_embeddings:\n",
        "            self.tgt_embedding = self.src_embedding\n",
        "            # Share embedding weights with output projection layer\n",
        "            # 定义输出投影层为一个lambda函数，实现将解码器输出的隐藏状态x映射到词表的logits空间\n",
        "            # 这里直接使用目标embedding层的权重矩阵（get_word_embedding_weights()），并对其进行转置\n",
        "            # 这样做的目的是让输出层与embedding层共享参数，节省内存并提升模型效果（类似于权重绑定/权重共享）\n",
        "            # torch.matmul实现批量矩阵乘法，将每个时间步的隐藏向量与embedding权重矩阵相乘，得到每个词的logits\n",
        "            self.output_projection = lambda x: torch.matmul(  # x是解码器输出的隐藏状态x\n",
        "                x, self.tgt_embedding.get_word_embedding_weights().T \n",
        "            )\n",
        "        else:\n",
        "            # 不共享embedding\n",
        "            self.tgt_embedding = TransformerEmbedding(config=config) # 创建目标语言的embedding层\n",
        "            self.output_projection = nn.Linear(self.d_model, self.vocab_size) # 创建输出投影层\n",
        "\n",
        "        # Encoder and Decoder\n",
        "        self.encoder = TransformerEncoder(config=config) # 创建编码器\n",
        "\n",
        "        self.decoder = TransformerDecoder(config=config) # 创建解码器\n",
        "\n",
        "        # Initialize parameters with Xavier uniform\n",
        "        # 调用初始化参数的方法，确保模型的权重在训练前被合理初始化\n",
        "        self._init_parameters() \n",
        "\n",
        "    # 定义一个私有方法用于初始化模型参数\n",
        "    def _init_parameters(self):\n",
        "        # 遍历模型中的所有参数\n",
        "        for p in self.parameters():\n",
        "            # 只对维度大于1的参数（如权重矩阵）进行初始化\n",
        "            if p.dim() > 1:\n",
        "                # 使用Xavier均匀分布对参数进行初始化，有助于保持前向和反向传播时的方差稳定\n",
        "                nn.init.xavier_uniform_(p)\n",
        "\n",
        "    def forward(\n",
        "        self, # 模型输入参数\n",
        "        src_inputs: torch.Tensor, # 源语言输入，shape为[batch_size, src_seq_len]\n",
        "        tgt_inputs: torch.Tensor, # 目标语言输入，shape为[batch_size, tgt_seq_len]\n",
        "        src_padding_mask: Optional[torch.Tensor] = None, # 源语言填充mask，shape为[batch_size, src_seq_len]\n",
        "        tgt_padding_mask: Optional[torch.Tensor] = None, # 目标语言填充mask，shape为[batch_size, tgt_seq_len]\n",
        "        teacher_forcing_ratio: float = 0.5,  # teacher_forcing_ratio用于控制训练时有多大概率使用“教师强制”策略，即用真实的目标词作为下一个输入而不是模型自己的预测结果，0.5表示有50%的概率采用教师强制\n",
        "    ) -> TransformerOutput:\n",
        "        batch_size, src_seq_len = src_inputs.size() # src_inputs的shape为[batch_size, src_seq_len]\n",
        "        bs, tgt_seq_len = tgt_inputs.size() # tgt_inputs的shape为[batch_size, tgt_seq_len]\n",
        "\n",
        "        src_padding_mask = src_padding_mask.unsqueeze(1).unsqueeze(2) # [batch_size, 1, 1, src_seq_len]\n",
        "\n",
        "        if tgt_padding_mask is None: \n",
        "            tgt_padding_mask = tgt_inputs == self.padl_token_id  # tgt_padding_mask的shape为[batch_size, tgt_seq_len]\n",
        "        else:\n",
        "            tgt_padding_mask = tgt_padding_mask.unsqueeze(1) # tgt_padding_mask的维度扩展到[batch_size, 1, tgt_seq_len] \n",
        "        # Create look-ahead mask for decoder，尺寸[tgt_seq_len, tgt_seq_len]\n",
        "        # look_ahead_mask尺寸是[tgt_seq_len, tgt_seq_len]\n",
        "        look_ahead_mask = generate_look_ahead_mask(tgt_seq_len).to(tgt_inputs.device) # 创建前瞻掩码，用于 decoder\n",
        "\n",
        "        # print(f\"tgt_padding_mask.shape:{tgt_padding_mask.shape}\")\n",
        "        \n",
        "        # 计算combined_mask，作用是将目标序列的padding mask和前瞻mask合并，确保解码器在自回归生成时既不能看到未来的词，也不会关注到padding位置\n",
        "        \n",
        "        combined_mask = torch.max( \n",
        "            # 先对tgt_padding_mask在第1维（即第二个维度）进行unsqueeze，变成[batch_size, 1, tgt_seq_len]\n",
        "            # 然后用repeat(1, tgt_seq_len, 1)在第1维复制tgt_seq_len次，得到[batch_size, tgt_seq_len, tgt_seq_len]\n",
        "            # 这样每个batch的每个目标序列位置都能对应一行padding mask，方便与look_ahead_mask做最大值合并\n",
        "            tgt_padding_mask.unsqueeze(1).repeat(1, tgt_seq_len, 1),\n",
        "            # look_ahead_mask 是一个形状为 [tgt_seq_len, tgt_seq_len] 的张量，用于实现解码器的前瞻掩码\n",
        "            # 其作用是保证解码器在生成第 t 个词时，只能看到前 t 个词，不能看到未来的信息（即后面的词）\n",
        "            # 具体来说，look_ahead_mask 的下三角部分为 0（表示可见），上三角部分为 1（表示不可见/被掩盖）\n",
        "            # 这样可以防止模型在训练时“偷看”未来的目标词，保证自回归生成的正确性\n",
        "            look_ahead_mask  \n",
        "        )\n",
        "        combined_mask = combined_mask.unsqueeze(\n",
        "            1\n",
        "        )  # 变为[batch_size, 1, tgt_seq_len, tgt_seq_len]\n",
        "        # print(f\"combined_mask.shape:{combined_mask.shape}\")\n",
        "\n",
        "        # Embeddings\n",
        "        src_embedded = self.src_embedding(src_inputs) # 源语言编码\n",
        "        tgt_embedded = self.tgt_embedding(tgt_inputs) # 目标语言编码\n",
        "\n",
        "        # 编码器模块计算\n",
        "        encoder_output = self.encoder(src_embedded, attention_mask=src_padding_mask)\n",
        "        # print(f\"src_padding_mask.shape:{src_padding_mask.shape}\")\n",
        "        # print(f\"combined_mask.shape:{combined_mask.shape}\")\n",
        "        # 解码器模块计算\n",
        "        decoder_output = self.decoder(\n",
        "            tgt_embedded, # 目标输入\n",
        "            encoder_output.last_hidden_states, # 编码器输出\n",
        "            self_attn_mask=combined_mask, # 自注意力mask\n",
        "            cross_attn_mask=src_padding_mask,  # 交叉注意力mask\n",
        "        )\n",
        "\n",
        "        # 分类层\n",
        "        logits = self.output_projection(decoder_output.last_hidden_states) # 输出层\n",
        "\n",
        "        return TransformerOutput(\n",
        "            logits=logits, # 预测结果\n",
        "            encoder_attentions=encoder_output.attn_scores, # 编码器注意力\n",
        "            decoder_attentions=decoder_output.self_attn_scores, # 解码器自注意力\n",
        "            cross_attentions=decoder_output.cross_attn_scores, # 解码器跨注意力\n",
        "        )\n",
        "\n",
        "    @torch.no_grad() # 禁用梯度计算\n",
        "    def infer(self, encoder_inputs, encoder_inputs_mask=None):\n",
        "\n",
        "        if encoder_inputs_mask is None:  # 应对多个样本同时进行推理\n",
        "            # 判断encoder_inputs中哪些位置是pad_idx（即padding的标记），返回一个与encoder_inputs同形状的布尔张量，pad位置为True，其余为False\n",
        "            encoder_inputs_mask = encoder_inputs.eq(self.pad_idx)\n",
        "\n",
        "        # encoder_inputs_mask的形状是[batch_size, seq_len]->[batch_size, 1, 1, seq_len]    \n",
        "        encoder_inputs_mask = encoder_inputs_mask.unsqueeze(1).unsqueeze(\n",
        "            2\n",
        "        )  # [batch_size, 1, 1, src_len],[1,src_len]相加时，会自动广播到[batch_size,1,src_len,src_len]\n",
        "        # look_ahead_mask的形状是[1, 1, seq_len, seq_len]\n",
        "        look_ahead_mask = generate_look_ahead_mask(self.max_length)\n",
        "        look_ahead_mask = (\n",
        "            look_ahead_mask.unsqueeze(0).unsqueeze(0).to(encoder_inputs.device)\n",
        "        )  # [1, 1, trg_len, trg_len]\n",
        "\n",
        "        # 做embedding\n",
        "        encoder_inputs_embeds = self.src_embedding(encoder_inputs)\n",
        "        encoder_outputs = self.encoder(\n",
        "            encoder_inputs_embeds,\n",
        "            encoder_inputs_mask\n",
        "        )\n",
        "        # 解码器模块计算\n",
        "        # 首先，创建一个长度为 batch_size（即 encoder_inputs.shape[0]）的列表，每个元素都是 self.bos_idx，表示每个样本的起始标记\n",
        "        # 使用 torch.Tensor 将该列表转换为一个一维浮点型张量\n",
        "        # 通过 reshape(-1, 1) 将其变为二维张量，形状为 [batch_size, 1]，每一行对应一个样本的起始标记\n",
        "        # 使用 .long() 方法将张量的数据类型转换为 long（整型），以便作为索引或类别标签使用\n",
        "        # 最后，调用 .to(device=encoder_inputs.device) 将张量移动到与 encoder_inputs 相同的设备（如 CPU 或 GPU），保证后续计算不会因设备不一致而报错\n",
        "        decoder_inputs = torch.Tensor([self.bos_idx] * encoder_inputs.shape[0]).reshape(-1, 1).long().to(device=encoder_inputs.device)\n",
        "        for cur_len in tqdm(range(1, self.max_length + 1)):\n",
        "            # 做decoder的embedding\n",
        "            decoder_inputs_embeds = self.tgt_embedding(decoder_inputs)\n",
        "            # 调用解码器，生成当前步的输出\n",
        "            decoder_outputs = self.decoder(\n",
        "                decoder_inputs_embeds,  # 当前解码器输入的嵌入表示\n",
        "                encoder_outputs.last_hidden_states,  # 编码器输出的隐藏状态，作为解码器的上下文信息\n",
        "                # look_ahead_mask用于实现自回归解码，保证每个位置只能看到当前位置及其之前的内容\n",
        "                look_ahead_mask[:, :, :cur_len, :cur_len],  # 解码器自注意力的mask，动态裁剪到当前步长\n",
        "                encoder_inputs_mask  # 之所以要传入编码器输入的padding mask，是为了防止解码器在跨注意力时关注到pad位置，从而避免无效信息干扰模型学习\n",
        "            )\n",
        "\n",
        "            logits = self.output_projection(decoder_outputs.last_hidden_states)  # (batch_size, trg_len, vocab_size)\n",
        "            next_token = logits.argmax(dim=-1)[:, -1:] #通过最大下标确定类别，[:, -1:]表示取最后一个结果\n",
        "            decoder_inputs = torch.cat([decoder_inputs, next_token], dim=-1) #预测输出拼接到输入中\n",
        "            #(decoder_inputs == self.eos_idx).sum(dim=-1)是判断样本中是否含有EOS标记\n",
        "            #all是每一个都为True，才会结束\n",
        "            if all((decoder_inputs == self.eos_idx).sum(dim=-1) > 0):\n",
        "                break\n",
        "        return TransformerOutput(\n",
        "            preds=decoder_inputs[:, 1:],  # 从解码器的输入中去除起始标记（BOS），只保留生成的预测序列\n",
        "            logits=logits, # # 返回的预测序列的logits\n",
        "            encoder_attentions=encoder_outputs.attn_scores, # 返回编码器的注意力分数\n",
        "            decoder_attentions=decoder_outputs.self_attn_scores, # 返回解码器的注意力分数\n",
        "            cross_attentions=decoder_outputs.cross_attn_scores, # 跨注意力分数\n",
        "        )"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a8469135",
      "metadata": {
        "id": "a8469135"
      },
      "source": [
        "# 损失函数"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "307583eb",
      "metadata": {
        "id": "307583eb"
      },
      "outputs": [],
      "source": [
        "class CrossEntropyWithPadding:\n",
        "    def __init__(self, config):\n",
        "        \n",
        "        # 从传入的配置字典 config 中获取键 \"label_smoothing\" 对应的值，并赋值给实例变量 self.label_smoothing\n",
        "        # 这样做的目的是将标签平滑（label smoothing）参数保存到当前损失函数对象中，后续在计算交叉熵损失时可以直接使用\n",
        "        # 标签平滑是一种正则化技术，通过将真实标签的概率分布进行平滑（即不是完全的 one-hot），可以缓解模型过拟合，提高泛化能力\n",
        "        # 例如，如果 label_smoothing=0.1，对于一个三分类问题，原本的 one-hot 标签 [1, 0, 0] 会被平滑为 [0.9, 0.05, 0.05]\n",
        "        # 这样模型在训练时不会对某一类别过于自信，有助于提升模型的鲁棒性\n",
        "        self.label_smoothing = config[\"label_smoothing\"]\n",
        "\n",
        "    def __call__(self, logits, labels, padding_mask=None):\n",
        "        # logits.shape = [batch size, sequence length, num of classes]\n",
        "        # labels.shape = [batch size, sequence length]\n",
        "        # padding_mask.shape = [batch size, sequence length]，decode_label_mask\n",
        "        bs, seq_len, nc = logits.shape # logits.shape = [batch size, sequence length, num of classes],num of classes是类别数\n",
        "        loss = F.cross_entropy(logits.reshape(bs * seq_len, nc), labels.reshape(-1), reduce=False, label_smoothing=self.label_smoothing) #label_smoothing表示随机将一个类别的概率设置为0.1，使得模型更加关注其他类别\n",
        "        if padding_mask is None:\n",
        "            loss = loss.mean()\n",
        "        else:\n",
        "            padding_mask = 1 - padding_mask.reshape(-1) #将padding_mask reshape成一维张量，mask部分为0，非mask部分为1\n",
        "            # 先将每个位置的损失 loss 与 padding_mask 相乘，只保留非 padding 位置的损失（padding 位置为0，非padding为1）\n",
        "            # 然后对所有非 padding 位置的损失求和\n",
        "            # 最后除以非 padding 位置的总数，实现对有效 token 的平均损失计算，避免 padding 部分影响损失值\n",
        "            loss = torch.mul(loss, padding_mask).sum() / padding_mask.sum()\n",
        "\n",
        "        return loss\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 39,
      "id": "d85aeade",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 449
        },
        "id": "d85aeade",
        "outputId": "c8382f4b-13fa-4713-aba1-81ceb522211e"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "[<matplotlib.lines.Line2D at 0x7e29a2f7b650>]"
            ]
          },
          "execution_count": 39,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "image/png": "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YrEwbdo0Xn75ZXr27Em3bt148cUX6dixI6NGjaq/mYqIiEijZXdhiY+P58yZM8yePZucnBwiIiJYv3591UWz2dnZuLn964mbYcOGsXTpUl544QVmzZpFz549Wb16Nf37968a89xzz1FcXMwTTzzBhQsXuOWWW1i/fj0+PrpmREREROrwPizOqiHfh0VEREQaRoO8D4uIiIiII6iwiIiIiNNTYRERERGnp8IiIiIiTk+FRURERJyeCouIiIg4PRUWERERcXoqLCIiIuL0VFhERETE6dn91vzO6rs37C0sLHRwEhEREamt787b13vjfZcpLEVFRQAEBwc7OImIiIjYq6ioCH9//6ve7zKfJWSz2Th16hS+vr5YLJZ6e9zCwkKCg4M5fvy4S35GkavPD1x/jq4+P3D9OWp+jZ+rz7Eh52eMoaioiI4dO1b78OTvc5lnWNzc3OjcuXODPb6fn59L/hB+x9XnB64/R1efH7j+HDW/xs/V59hQ87vWMyvf0UW3IiIi4vRUWERERMTpqbBch7e3N3PmzMHb29vRURqEq88PXH+Orj4/cP05an6Nn6vP0Rnm5zIX3YqIiIjr0jMsIiIi4vRUWERERMTpqbCIiIiI01NhEREREaenwnIdixcvJiQkBB8fH6Kjo9m6daujI13h17/+NRaLpdotNDS06v7S0lImTpxI27ZtadmyJQ8++CC5ubnVHiM7O5uRI0fSvHlz2rdvz/Tp06msrKw2ZuPGjURFReHt7U2PHj14++23G2Q+X3zxBffccw8dO3bEYrGwevXqavcbY5g9ezYdOnSgWbNmxMbGcuDAgWpjzp07x9ixY/Hz86NVq1Y89thjXLx4sdqYHTt2cOutt+Lj40NwcDC///3vr8iycuVKQkND8fHxISwsjHXr1t2QOf7sZz+74pjeeeedjWaOSUlJDB48GF9fX9q3b8+oUaPYt29ftTE38ueyvn+PazO/22+//Ypj+OSTTzaK+QG88cYbDBgwoOqNwmJiYvj444+r7m/Mx68282vsx+/75s6di8ViYdq0aVXbGt0xNHJVy5cvN15eXuavf/2r2bVrl3n88cdNq1atTG5urqOjVTNnzhzTr18/c/r06arbmTNnqu5/8sknTXBwsElJSTHbtm0zQ4cONcOGDau6v7Ky0vTv39/ExsaajIwMs27dOhMQEGBmzpxZNebw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QECAycvLM8Zcfulaly5dzGeffWa2bdtmYmJiTExMTNX+37107Y477jCZmZlm/fr1pl27djW+dG369Olmz549ZvHixQ32suaioiKTkZFhMjIyDGBee+01k5GRYY4dO2aMufyy5latWpkPP/zQ7Nixw9x33301vqw5MjLSfPPNN+bLL780PXv2rPaS3wsXLpjAwEDz6KOPmqysLLN8+XLTvHnzK17y6+HhYebNm2f27Nlj5syZU28va77WHIuKisyzzz5rUlNTzZEjR8ynn35qoqKiTM+ePU1paWmjmONTTz1l/P39zcaNG6u9LLSkpKRqzI36uWyI3+Prze/gwYPmN7/5jdm2bZs5cuSI+fDDD0337t3Nbbfd1ijmZ4wxM2bMMJs2bTJHjhwxO3bsMDNmzDAWi8X885//NMY07uN3vfm5wvGryfdf+dTYjqEKy3UsWrTIdOnSxXh5eZkhQ4aYr7/+2tGRrhAfH286dOhgvLy8TKdOnUx8fLw5ePBg1f2XLl0yv/zlL03r1q1N8+bNzf33329Onz5d7TGOHj1q7rrrLtOsWTMTEBBgnnnmGVNRUVFtzOeff24iIiKMl5eX6d69u3nrrbcaZD6ff/65Aa64jR8/3hhz+aXNL774ogkMDDTe3t5mxIgRZt++fdUe4+zZsyYhIcG0bNnS+Pn5mQkTJpiioqJqY7Zv325uueUW4+3tbTp16mTmzp17RZZ3333X9OrVy3h5eZl+/fqZjz76qMHnWFJSYu644w7Trl074+npabp27Woef/zxK365nXmONc0NqPYzcyN/Luv79/h688vOzja33XabadOmjfH29jY9evQw06dPr/Y+Hs48P2OM+fnPf266du1qvLy8TLt27cyIESOqyooxjfv4XW9+rnD8avL9wtLYjqHFGGPse05GRERE5MbSNSwiIiLi9FRYRERExOmpsIiIiIjTU2ERERERp6fCIiIiIk5PhUVEREScngqLiIiIOD0VFhEREXF6KiwiIiLi9FRYRERExOmpsIiIiIjTU2ERERERp/d/WvhGRCRCR7sAAAAASUVORK5CYII=",
            "text/plain": [
              "<Figure size 640x480 with 1 Axes>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "x=np.arange(1, 40000)\n",
        "plt.plot(x, x * (4000 ** (-1.5)))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "63402af1",
      "metadata": {
        "id": "63402af1"
      },
      "source": [
        "# Warmup技术"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "36aef5d6",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 449
        },
        "id": "36aef5d6",
        "outputId": "70f00d93-b6d9-4c42-eb1b-ccdb432cc3c9"
      },
      "outputs": [
        {
          "data": {
            "image/png": "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",
            "text/plain": [
              "<Figure size 640x480 with 1 Axes>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "# NoamDecayScheduler 是一个自定义或外部定义的学习率衰减调度器类。它需要接收配置 config 作为参数，可以实现了特定的学习率衰减方案\n",
        "class NoamDecayScheduler:\n",
        "    def __init__(self, config):\n",
        "        self.d_model = config[\"d_model\"]  # 获取模型的维度大小\n",
        "        self.warmup_steps = config[\"warmup_steps\"]  # 获取预热步数\n",
        "\n",
        "    def __call__(self, step): # 调度器的调用方法\n",
        "        step += 1  # 步数从1开始计算，而不是0\n",
        "        arg1 = step ** (-0.5)  # 4000步之后是arg1，计算步数的-0.5次方，公式：1/sqrt(step)\n",
        "        arg2 = step * (self.warmup_steps ** (-1.5))  # 4000步之前是arg2，计算步数乘以预热步数的-1.5次方\n",
        "\n",
        "        arg3 = self.d_model ** (-0.5)  # 计算模型维度的-0.5次方\n",
        "\n",
        "        return arg3 * np.minimum(arg1, arg2)  # 返回学习率，取arg1和arg2的较小值乘以arg3\n",
        "\n",
        "\n",
        "temp_learning_rate_schedule = NoamDecayScheduler({\"d_model\": 512, \"warmup_steps\": 4000})  # 创建学习率调度器实例，设置模型维度为512，预热步数为4000\n",
        "#下面是学习率的设计图\n",
        "plt.plot(temp_learning_rate_schedule(np.arange(0, 40000)))  # 绘制学习率曲线，横轴为0到40000的步数\n",
        "plt.ylabel(\"Leraning rate\")  # 设置y轴标签为\"学习率\"\n",
        "plt.xlabel(\"Train step\")  # 设置x轴标签为\"训练步数\"\n",
        "plt.grid()  # 显示网格线\n",
        "plt.show()  # 显示图表\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "f94aa6ef",
      "metadata": {
        "id": "f94aa6ef"
      },
      "outputs": [],
      "source": [
        "from torch.optim.lr_scheduler import LambdaLR\n",
        "from torch.optim import Adam\n",
        "\n",
        "def get_optimizer(model, config):\n",
        "    base_lr = config['base_lr']\n",
        "    beta1 = config[\"beta1\"] # Adam 的 beta1\n",
        "    beta2 = config[\"beta2\"] # Adam 的 beta2\n",
        "    eps = config[\"eps\"] \n",
        "    optimizer = Adam(model.parameters(), lr=base_lr, betas=(beta1, beta2), eps=eps)  # eps用于防止分母为零，提高数值稳定性\n",
        "    lr_scheduler1 = NoamDecayScheduler(config) #config是一个字典，包含了学习率衰减的参数，NoamDecayScheduler是一个自定义的调度器，用于实现Noam学习率衰减\n",
        "    # 使用 LambdaLR 调度器，它可以根据给定的函数 lr_lambda 调整学习率。这里将 lr_scheduler 作为函数传递给 LambdaLR，它包含了特定于模型或任务的学习率调度规则\n",
        "    scheduler = LambdaLR(optimizer, lr_lambda=lr_scheduler1)\n",
        "    return optimizer, scheduler"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0505aea6",
      "metadata": {
        "id": "0505aea6"
      },
      "source": [
        "# 保存模型，早停"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 42,
      "id": "486fb390",
      "metadata": {
        "id": "486fb390"
      },
      "outputs": [],
      "source": [
        "class SaveCheckpointsCallback:\n",
        "    def __init__(self, save_dir, save_step=5000, save_best_only=True):\n",
        "        \"\"\"\n",
        "        Save checkpoints each save_epoch epoch.\n",
        "        We save checkpoint by epoch in this implementation.\n",
        "        Usually, training scripts with pytorch evaluating model and save checkpoint by step.\n",
        "\n",
        "        Args:\n",
        "            save_dir (str): dir to save checkpoint\n",
        "            save_epoch (int, optional): the frequency to save checkpoint. Defaults to 1.\n",
        "            save_best_only (bool, optional): If True, only save the best model or save each model at every epoch.\n",
        "        \"\"\"\n",
        "        self.save_dir = save_dir\n",
        "        self.save_step = save_step\n",
        "        self.save_best_only = save_best_only\n",
        "        self.best_metrics = - np.inf\n",
        "\n",
        "        # mkdir\n",
        "        if not os.path.exists(self.save_dir):\n",
        "            os.mkdir(self.save_dir)\n",
        "\n",
        "    def __call__(self, step, state_dict, metric=None):\n",
        "        if step % self.save_step > 0:\n",
        "            return\n",
        "\n",
        "        if self.save_best_only:\n",
        "            assert metric is not None\n",
        "            if metric >= self.best_metrics:\n",
        "                # save checkpoints\n",
        "                torch.save(state_dict, os.path.join(self.save_dir, \"best.ckpt\"))\n",
        "                # update best metrics\n",
        "                self.best_metrics = metric\n",
        "        else:\n",
        "            torch.save(state_dict, os.path.join(self.save_dir, f\"{step}.ckpt\"))\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 43,
      "id": "ba9e24af",
      "metadata": {
        "id": "ba9e24af"
      },
      "outputs": [],
      "source": [
        "class EarlyStopCallback:\n",
        "    def __init__(self, patience=5, min_delta=0.01):\n",
        "        \"\"\"\n",
        "\n",
        "        Args:\n",
        "            patience (int, optional): Number of epochs with no improvement after which training will be stopped.. Defaults to 5.\n",
        "            min_delta (float, optional): Minimum change in the monitored quantity to qualify as an improvement, i.e. an absolute\n",
        "                change of less than min_delta, will count as no improvement. Defaults to 0.01.\n",
        "        \"\"\"\n",
        "        self.patience = patience\n",
        "        self.min_delta = min_delta\n",
        "        self.best_metric = - np.inf\n",
        "        self.counter = 0\n",
        "\n",
        "    def __call__(self, metric):\n",
        "        if metric >= self.best_metric + self.min_delta:\n",
        "            # update best metric\n",
        "            self.best_metric = metric\n",
        "            # reset counter\n",
        "            self.counter = 0\n",
        "        else:\n",
        "            self.counter += 1\n",
        "\n",
        "    @property\n",
        "    def early_stop(self):\n",
        "        return self.counter >= self.patience\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "3b3dc4fb",
      "metadata": {
        "id": "3b3dc4fb"
      },
      "source": [
        "# 评估，训练"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 44,
      "id": "7d854676",
      "metadata": {
        "id": "7d854676"
      },
      "outputs": [],
      "source": [
        "@torch.no_grad()\n",
        "def evaluating(model, dataloader, loss_fct):\n",
        "    loss_list = []\n",
        "    for batch in dataloader:\n",
        "        encoder_inputs = batch[\"encoder_inputs\"]\n",
        "        encoder_inputs_mask = batch[\"encoder_inputs_mask\"]\n",
        "        decoder_inputs = batch[\"decoder_inputs\"]\n",
        "        decoder_labels = batch[\"decoder_labels\"]\n",
        "        decoder_labels_mask = batch[\"decoder_labels_mask\"]\n",
        "\n",
        "        # 前向计算\n",
        "        outputs = model(\n",
        "            encoder_inputs,\n",
        "            decoder_inputs,\n",
        "            encoder_inputs_mask\n",
        "            )\n",
        "        logits = outputs.logits\n",
        "        loss = loss_fct(logits, decoder_labels, padding_mask=decoder_labels_mask)         # 验证集损失\n",
        "        loss_list.append(loss.cpu().item())\n",
        "\n",
        "    return np.mean(loss_list)\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "753f1655",
      "metadata": {
        "id": "753f1655"
      },
      "outputs": [],
      "source": [
        "# 训练\n",
        "def training(\n",
        "    model, # 模型\n",
        "    train_loader, # 训练数据集\n",
        "    val_loader, # 验证数据集\n",
        "    epoch, # 训练轮数\n",
        "    loss_fct, # 损失函数\n",
        "    optimizer, # 优化器\n",
        "    scheduler=None, # 调度器\n",
        "    tensorboard_callback=None, # Tensorboard回调函数\n",
        "    save_ckpt_callback=None, # 保存模型回调函数 \n",
        "    early_stop_callback=None, # 提前停止回调函数\n",
        "    eval_step=500, # 评估步数\n",
        "    ):\n",
        "    record_dict = {\n",
        "        \"train\": [],\n",
        "        \"val\": []\n",
        "    }\n",
        "\n",
        "    global_step = 1\n",
        "    val_loss = 0\n",
        "    model.train()\n",
        "    with tqdm(total=epoch * len(train_loader)) as pbar:\n",
        "        for epoch_id in range(epoch): # 训练轮数\n",
        "            # training\n",
        "            for batch in train_loader: # 训练数据\n",
        "                encoder_inputs = batch[\"encoder_inputs\"]\n",
        "                encoder_inputs_mask = batch[\"encoder_inputs_mask\"]\n",
        "                decoder_inputs = batch[\"decoder_inputs\"]\n",
        "                decoder_labels = batch[\"decoder_labels\"]\n",
        "                decoder_labels_mask = batch[\"decoder_labels_mask\"]\n",
        "                # 梯度清空\n",
        "                optimizer.zero_grad()\n",
        "\n",
        "                # 前向计算\n",
        "                outputs = model(\n",
        "                    encoder_inputs,\n",
        "                    decoder_inputs,\n",
        "                    encoder_inputs_mask\n",
        "                    )\n",
        "                logits = outputs.logits\n",
        "                loss = loss_fct(logits, decoder_labels, padding_mask=decoder_labels_mask)\n",
        "\n",
        "                # 梯度回传\n",
        "                loss.backward()\n",
        "\n",
        "                # 调整优化器，包括学习率的变动等\n",
        "                optimizer.step()\n",
        "                if scheduler is not None:\n",
        "                    scheduler.step() # 更新学习率,学习率就会传递给optimizer\n",
        "\n",
        "                # 将损失张量从GPU移动到CPU，并将其转换为Python的float类型，方便后续记录和打印\n",
        "                loss = loss.cpu().item() \n",
        "                # record\n",
        "                record_dict[\"train\"].append({\n",
        "                    \"loss\": loss, \"step\": global_step\n",
        "                })\n",
        "\n",
        "                # evaluating\n",
        "                if global_step % eval_step == 0:\n",
        "                    model.eval()\n",
        "                    val_loss = evaluating(model, val_loader, loss_fct)\n",
        "                    record_dict[\"val\"].append({\n",
        "                        \"loss\": val_loss, \"step\": global_step\n",
        "                    })\n",
        "                    model.train()\n",
        "\n",
        "                    # 2. 保存模型权重 save model checkpoint\n",
        "                    if save_ckpt_callback is not None:\n",
        "                        save_ckpt_callback(global_step, model.state_dict(), metric=-val_loss)\n",
        "\n",
        "                    # 3. 早停 Early Stop\n",
        "                    if early_stop_callback is not None:\n",
        "                        early_stop_callback(-val_loss)\n",
        "                        if early_stop_callback.early_stop:\n",
        "                            print(f\"Early stop at epoch {epoch_id} / global_step {global_step}\")\n",
        "                            return record_dict\n",
        "\n",
        "                # udate step\n",
        "                global_step += 1\n",
        "                pbar.update(1)\n",
        "                pbar.set_postfix({\"epoch\": epoch_id, \"loss\": loss, \"val_loss\": val_loss})\n",
        "\n",
        "    return record_dict\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "17dd83e9",
      "metadata": {
        "id": "17dd83e9"
      },
      "source": [
        "# 开始训练"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "5ee7ed1b",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "5ee7ed1b",
        "outputId": "d94c349e-3a4d-40c0-ff4f-d363262a4044"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "save cache to wmt16/.cache/de2en_train_100.npy\n",
            "save cache to wmt16/.cache/de2en_val_100.npy\n"
          ]
        }
      ],
      "source": [
        "# 数据加载器\n",
        "def get_dl(dataset, batch_size, shuffle=True):\n",
        "    # 创建一个批采样器，用于根据batch_size和是否打乱来生成批次索引\n",
        "    sampler = TransformerBatchSampler(dataset, batch_size=batch_size, shuffle_batch=shuffle)\n",
        "    # 使用DataLoader加载数据集，指定批采样器和自定义的collate函数（用于处理批数据的拼接和tokenizer处理）\n",
        "    sample_dl = DataLoader(dataset, batch_sampler=sampler, collate_fn=partial(collate_fct, tokenizer=tokenizer))\n",
        "    # 返回构建好的DataLoader对象\n",
        "    return sample_dl\n",
        "\n",
        "# dataset\n",
        "train_ds = LangPairDataset(\"train\", max_length=config[\"max_length\"])\n",
        "val_ds = LangPairDataset(\"val\", max_length=config[\"max_length\"])\n",
        "# tokenizer\n",
        "tokenizer = Tokenizer(word2idx=word2idx, idx2word=idx2word, max_length=config[\"max_length\"])\n",
        "batch_size = 4096\n",
        "# dataloader\n",
        "train_dl = get_dl(train_ds, batch_size=batch_size, shuffle=True)\n",
        "val_dl = get_dl(val_ds, batch_size=batch_size, shuffle=False)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 47,
      "id": "9da25003",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "9da25003",
        "outputId": "92d93710-2919-4315-b168-db8a1db18abd"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "140"
            ]
          },
          "execution_count": 47,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "len(train_dl)*20"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "dfdfb28b",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 126,
          "referenced_widgets": [
            "7fff264309184763be76c74febde5af1",
            "a51848bc90674b5bbfe6aa10b1fbd92b",
            "f713cc5ab93e467699537e1033853259",
            "880ed6db148b41fe93ccf987173c95b0",
            "b0af4291ebd44162bc27b36c1ad3f651",
            "eac3d467f0e24fc5a461c4f5037d76da",
            "56b020a70cd34c1c9673d7ebdba23c43",
            "7d1e98340eb54ca7be701aba5cf76943",
            "d3ac645daf904649988e69aa58fb665a",
            "928f41cfb6184310afb07d861c17a413",
            "91c3e9b25c94440181ce6e679ef357c3"
          ]
        },
        "id": "dfdfb28b",
        "outputId": "ecce7e6d-015d-4228-8e1c-377a1851aebd"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "模型总参数量: 71,975,103\n"
          ]
        },
        {
          "data": {
            "application/vnd.jupyter.widget-view+json": {
              "model_id": "7fff264309184763be76c74febde5af1",
              "version_major": 2,
              "version_minor": 0
            },
            "text/plain": [
              "  0%|          | 0/17160 [00:00<?, ?it/s]"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "/usr/local/lib/python3.11/dist-packages/torch/nn/_reduction.py:51: UserWarning: size_average and reduce args will be deprecated, please use reduction='none' instead.\n",
            "  warnings.warn(warning.format(ret))\n"
          ]
        }
      ],
      "source": [
        "#模型的超参\n",
        "config = {\n",
        "    \"bos_idx\": 1,\n",
        "    \"eos_idx\": 3,\n",
        "    \"pad_idx\": 0,\n",
        "    \"vocab_size\": len(word2idx),\n",
        "    \"max_length\": 128,#seq_len最大长度\n",
        "    \"d_model\": 512,#可以调整\n",
        "    \"dim_feedforward\": 2048, # FFN 的隐藏层大小\n",
        "    \"dropout\": 0.1,#可以调整\n",
        "    \"layer_norm_eps\": 1e-6, # 层归一化的 epsilon, 防止除零错误\n",
        "    \"num_heads\": 8,#论文里是8，可以调整\n",
        "    \"num_decoder_layers\": 6, #论文是6，可以调整\n",
        "    \"num_encoder_layers\": 6, #论文是6，可以调整\n",
        "    \"label_smoothing\": 0.1,#标签平滑，防止过拟合\n",
        "    \"beta1\": 0.9, # Adam 的 beta1\n",
        "    \"beta2\": 0.98,\n",
        "    \"eps\": 1e-9, # Adam 的 epsilon\n",
        "    \"warmup_steps\": 4000,\n",
        "    \"share_embedding\": False, # 是否共享词向量，如果改为True，效果不好\n",
        "    \"base_lr\": 0.1,\n",
        "    }\n",
        "epoch = 20\n",
        "\n",
        "# model\n",
        "model = TransformerModel(config)\n",
        "# 计算模型参数量\n",
        "def count_parameters(model):\n",
        "    return sum(p.numel() for p in model.parameters() if p.requires_grad)\n",
        "\n",
        "total_params = count_parameters(model)\n",
        "print(f\"模型总参数量: {total_params:,}\")\n",
        "\n",
        "\n",
        "\n",
        "# 1. 定义损失函数 采用交叉熵损失\n",
        "loss_fct = CrossEntropyWithPadding(config)\n",
        "# 2. 定义优化器 采用 adam\n",
        "# Optimizers specified in the torch.optim package\n",
        "optimizer, scheduler = get_optimizer(model, config)\n",
        "\n",
        "# 模型保存\n",
        "if not os.path.exists(\"checkpoints\"):\n",
        "    os.makedirs(\"checkpoints\")\n",
        "save_ckpt_callback = SaveCheckpointsCallback(\n",
        "    f\"checkpoints\", save_step=500, save_best_only=True)\n",
        "# 3. early stop\n",
        "early_stop_callback = EarlyStopCallback(patience=8)\n",
        "\n",
        "model = model.to(device)\n",
        "\n",
        "record = training(\n",
        "    model,\n",
        "    train_dl,\n",
        "    val_dl,\n",
        "    epoch,\n",
        "    loss_fct,\n",
        "    optimizer,\n",
        "    scheduler,\n",
        "    tensorboard_callback=None,\n",
        "    save_ckpt_callback=save_ckpt_callback,\n",
        "    early_stop_callback=None,\n",
        "    eval_step=500\n",
        "    )"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "xeEbSABIGmp5",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 446,
          "referenced_widgets": [
            "381277e910d647b98475c7e514d4ce59",
            "79e7a2f67e704862b46c4479a28aa57e",
            "530f7729ef174321868689c813cbab16",
            "6ceb216821134bffaacd542be9332afd",
            "b4f510c9bb9144ccb2fb6381ad2959b1",
            "260f33f2bfc745cf904790692b45daa3",
            "3a96896a8b1746b08d855322fc274a7c",
            "da3d1cec9148455ea084b22d7209805e",
            "512ed7c39b0a49ed97c4ed9aa9cb47e9",
            "6ada793910ae47b0953f6be510d7d935",
            "7045995d4587482c8d87797846e13ad9"
          ]
        },
        "id": "xeEbSABIGmp5",
        "outputId": "1046eae4-1991-4ccd-cb69-49c54f825a4c"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "save cache to wmt16/.cache/de2en_test_128.npy\n"
          ]
        },
        {
          "data": {
            "application/vnd.jupyter.widget-view+json": {
              "model_id": "381277e910d647b98475c7e514d4ce59",
              "version_major": 2,
              "version_minor": 0
            },
            "text/plain": [
              "0it [00:00, ?it/s]"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "/usr/local/lib/python3.11/dist-packages/nltk/translate/bleu_score.py:577: UserWarning: \n",
            "The hypothesis contains 0 counts of 4-gram overlaps.\n",
            "Therefore the BLEU score evaluates to 0, independently of\n",
            "how many N-gram overlaps of lower order it contains.\n",
            "Consider using lower n-gram order or use SmoothingFunction()\n",
            "  warnings.warn(_msg)\n",
            "/usr/local/lib/python3.11/dist-packages/nltk/translate/bleu_score.py:577: UserWarning: \n",
            "The hypothesis contains 0 counts of 3-gram overlaps.\n",
            "Therefore the BLEU score evaluates to 0, independently of\n",
            "how many N-gram overlaps of lower order it contains.\n",
            "Consider using lower n-gram order or use SmoothingFunction()\n",
            "  warnings.warn(_msg)\n",
            "/usr/local/lib/python3.11/dist-packages/nltk/translate/bleu_score.py:577: UserWarning: \n",
            "The hypothesis contains 0 counts of 2-gram overlaps.\n",
            "Therefore the BLEU score evaluates to 0, independently of\n",
            "how many N-gram overlaps of lower order it contains.\n",
            "Consider using lower n-gram order or use SmoothingFunction()\n",
            "  warnings.warn(_msg)\n"
          ]
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "testing loss: 3.5472568195799123\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "0.5363600692116299"
            ]
          },
          "execution_count": 49,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# 导入用于计算BLEU分数的函数\n",
        "from nltk.translate.bleu_score import sentence_bleu  # 导入sentence_bleu用于BLEU分数计算\n",
        "# 加载模型权重\n",
        "model = TransformerModel(config)  # 初始化Transformer模型\n",
        "state_dict = torch.load(\"checkpoints/best.ckpt\")  # 加载最优模型的参数字典\n",
        "model.load_state_dict(state_dict)  # 将参数加载到模型中\n",
        "\n",
        "loss_fct = CrossEntropyWithPadding(config)  # 定义带有padding的交叉熵损失函数\n",
        "# 构建测试集数据集\n",
        "test_ds = LangPairDataset(\"test\", max_length=128, data_dir=\"./wmt16\")  # 创建测试集数据集对象\n",
        "test_dl = DataLoader(test_ds, batch_size=1, collate_fn=partial(collate_fct, tokenizer=tokenizer))  # 创建测试集数据加载器，batch_size为1\n",
        "\n",
        "model = model.to(device)  # 将模型移动到指定设备（如GPU）\n",
        "model.eval()  # 设置模型为评估模式\n",
        "collect = {}  # 用于收集每个样本的结果\n",
        "loss_collect = []  # 用于收集每个样本的损失\n",
        "\n",
        "predictions = []  # 预测结果列表（未使用）\n",
        "answers = []  # 真实标签列表（未使用）\n",
        "bleu_scores = []  # 用于存储每个样本的BLEU分数\n",
        "for idx, batch in tqdm(enumerate(test_dl)):  # 遍历测试集中的每个batch\n",
        "    encoder_inputs = batch[\"encoder_inputs\"]  # 获取编码器输入\n",
        "    encoder_inputs_mask = batch[\"encoder_inputs_mask\"]  # 获取编码器输入的mask\n",
        "    decoder_inputs = batch[\"decoder_inputs\"]  # 获取解码器输入\n",
        "    decoder_labels = batch[\"decoder_labels\"]  # 获取解码器标签\n",
        "    # 前向传播，获取模型输出\n",
        "    outputs = model(\n",
        "        encoder_inputs,  # 编码器输入\n",
        "        decoder_inputs,  # 解码器输入\n",
        "        encoder_inputs_mask  # 编码器输入mask\n",
        "        )\n",
        "    loss = loss_fct(outputs.logits, decoder_labels)  # 计算损失\n",
        "\n",
        "    preds = outputs.logits.argmax(dim=-1)  # 获取预测的token索引（取最大概率的类别）\n",
        "    preds = tokenizer.decode(preds.cpu().numpy())  # 将预测的token索引解码为英文句子\n",
        "    decoder_labels = tokenizer.decode(decoder_labels.cpu().numpy())  # 将真实标签token索引解码为英文句子\n",
        "    belu = sentence_bleu([decoder_labels[0].split()], preds[0].split(), weights=(1, 0, 0, 0))  # 计算BLEU分数（unigram）\n",
        "    bleu_scores.append(belu)  # 将BLEU分数添加到列表\n",
        "    collect[idx] = {  # 收集当前样本的相关信息\n",
        "        \"loss\": loss.item(),  # 损失值\n",
        "        \"src_inputs\": encoder_inputs,  # 源语言输入\n",
        "        \"trg_inputs\": decoder_inputs,  # 目标语言输入\n",
        "        \"mask\": encoder_inputs_mask,  # mask\n",
        "        \"trg_labels\": decoder_labels,  # 真实标签\n",
        "        \"preds\": preds  # 预测结果\n",
        "    }\n",
        "    loss_collect.append(loss.item())  # 收集损失值\n",
        "\n",
        "# 按照损失值对collect排序\n",
        "collect = sorted(collect.items(), key=lambda x: x[1][\"loss\"])  # 按损失升序排序\n",
        "print(f\"testing loss: {np.array(loss_collect).mean()}\")  # 打印测试集平均损失\n",
        "sum(bleu_scores) / len(bleu_scores)  # 计算并输出测试集BLEU分数的平均值"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 51,
      "id": "XQUq1g_zG5Q-",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "XQUq1g_zG5Q-",
        "outputId": "1a81cbee-8c8d-4aeb-b2a9-b476f7ccf2c9"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Requirement already satisfied: Cython in /usr/local/lib/python3.11/dist-packages (3.0.12)\n",
            "Collecting fastBPE\n",
            "  Downloading fastBPE-0.1.0.tar.gz (35 kB)\n",
            "  Preparing metadata (setup.py) ... \u001b[?25l\u001b[?25hdone\n",
            "Building wheels for collected packages: fastBPE\n",
            "  Building wheel for fastBPE (setup.py) ... \u001b[?25l\u001b[?25hdone\n",
            "  Created wheel for fastBPE: filename=fastBPE-0.1.0-cp311-cp311-linux_x86_64.whl size=809501 sha256=c74074a43301345f7c5b9464e8c7088372ac28490f6d6c03302f4d3e422905f6\n",
            "  Stored in directory: /root/.cache/pip/wheels/73/78/50/cd953038d211e114145aa29ed48c3ac825746309dd01929e74\n",
            "Successfully built fastBPE\n",
            "Installing collected packages: fastBPE\n",
            "Successfully installed fastBPE-0.1.0\n"
          ]
        }
      ],
      "source": [
        "!pip install Cython  # if failed to install fastBPE, try this line\n",
        "!pip install fastBPE #分词使用，分词直接在内存中进行，无需把数据写入文件，用subword-nmt命令"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "adzdtLeMGqCF",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 629,
          "referenced_widgets": [
            "3212f3a98f5e4a96ac888f368f4fff42",
            "8af2647d8486443a8a025bc30e9ddac6",
            "280b011dc683465985da449bc80ab71f",
            "16ae7acad596458890f112a68c515cdf",
            "f6971c6f2b22427cb2b58ffffda71135",
            "d939b58e958641bdb4f2a2accc1c3645",
            "5b30c15446eb4a6cbc62498fb6753323",
            "046c17ba17f94587968cda8c761c2bf7",
            "79a55387adba484e9485779a07bcc8e9",
            "ec9417d5c4e54d18966e0140e60e4f7e",
            "2d5c3abf516b48b6946778709ac9d97d"
          ]
        },
        "id": "adzdtLeMGqCF",
        "outputId": "a20404fb-2502-447d-cf41-7cdae9e86290"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "[['ein', 'mann', 'mit', 'einem', 'eimer', 'und', 'ein', 'mädchen', 'mit', 'einem', 'hut', 'am', 'strand', '.']]\n"
          ]
        },
        {
          "data": {
            "application/vnd.jupyter.widget-view+json": {
              "model_id": "3212f3a98f5e4a96ac888f368f4fff42",
              "version_major": 2,
              "version_minor": 0
            },
            "text/plain": [
              "  0%|          | 0/128 [00:00<?, ?it/s]"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "/usr/local/lib/python3.11/dist-packages/IPython/core/pylabtools.py:151: UserWarning: There are no gridspecs with layoutgrids. Possibly did not call parent GridSpec with the \"figure\" keyword\n",
            "  fig.canvas.print_figure(bytes_io, **kw)\n"
          ]
        },
        {
          "data": {
            "image/png": "iVBORw0KGgoAAAANSUhEUgAAA0IAAAHkCAYAAAAThJ+uAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAZD1JREFUeJzt3Xd4lGXe/v9zJmXSSAKhJGAgIKGG4oo0QUDZxYKryLLKIoodK3WRiKCxEB8sgGV1RQX0UdDHvquCigZFmpQAEqQEMFFBJEhCKAnJ3L8/+DI/xiRCkrkyuTPv13HMQabknE8u7plrPnM3h2VZlgAAAAAggDj9XQAAAAAA1DQaIQAAAAABh0YIAAAAQMChEQIAAAAQcGiEAAAAAAQcGiEAAAAAAYdGCAAAAEDAoRECAAAAEHBohAAAAAAEHBohAAAAAAGHRggAAABAwKERAgAAABBwaIQAAAAABJxgfxcAAACA2m379u368ssvtW/fPrndbq/7pk2b5qeqgOpxWJZl+bsIAAAA1E5z5szR7bffroYNGyo+Pl4Oh8Nzn8Ph0Lp16/xYHVB1NEIAAACoUIsWLXTHHXfo3nvv9XcpgE/RCAEAAKBC0dHRyszMVKtWrfxdCuBTHCwBAAAAFRo2bJg+/fRTf5cB+BwHSwAAAECFWrduralTp2rlypXq1KmTQkJCvO6/5557/FQZUD1sGgcAAIAKtWzZssL7HA6Hdu7cWYPVAL5DIwQAAAAg4LCPEAAAAE6ruLhYW7duVUlJib9LAXyCRggAAAAVOnLkiG666SZFRESoY8eOysnJkSTdfffdeuyxx/xcHVB1NEIAAACoUGpqqjZs2KCMjAyFhYV5bh84cKDefPNNP1YGVA9HjQMAAECF3n//fb355pvq2bOnHA6H5/aOHTsqOzvbj5UB1cMaIQAAAFTo119/VePGjcvcfvjwYa/GCLAbGiEAAABUqFu3bvroo4881082Py+99JJ69erlr7KAamPTOAAAAFRo+vTpuuSSS5SVlaWSkhLNnj1bWVlZWr58uZYuXerv8oAqY40QAAAAKtSnTx9lZmaqpKREnTp10qeffqrGjRtrxYoVOvfcc/1dHlBlnFAVAAAAQMBh0zgAAAD8IbfbrR07dmjfvn1yu91e911wwQV+qgqoHhohAAAAVGjlypX6xz/+oR9++EG/35DI4XCotLTUT5UB1cOmcQAAAKhQ165d1aZNG6WlpSkhIaHMIbNjYmL8VBkq8uGHH57xY//6178arKR2oxECAABAhSIjI7Vhwwa1bt3a36XgDDmd3sdDczgcXmvzTm1mA3mNHkeNAwAAtpOXl6c777xTHTp0UMOGDdWgQQOvC3ynR48e2rFjh7/LqJRAXz7cbrfn8umnn6pr16765JNPdPDgQR08eFAff/yx/vSnP2nRokX+LtWv2EcIAHyMnYq9MR4wYeTIkdqxY4duuukmNWnSpMzmWlVhWZZyc3PVuHFjhYWF+aBK+9q4caPn57vvvlsTJkzQ3r171alTJ4WEhHg9tnPnzjVd3mmZWD7sauzYsXrhhRfUp08fz22DBg1SRESEbr31Vm3ZssWP1fkXm8YBgA+xU7E3xgOm1KtXT8uWLVOXLl18lul2uxUWFqbNmzcrOTnZZ7l25HQ6y2xOdaqT99XW17GJ5cOuwsPD9e233yolJcXr9o0bN6pHjx46evSonyrzP9YIAYAPjR49Wt26ddNHH31U7k7FgYbxgCnt2rXz+Qc4p9Op5ORk5eXlBXwjtGvXLn+XUC0mlg+7Ou+88zR+/Hi99tpratKkiSTpl19+0T//+U91797dz9X5F2uETvGnP/2pUo93OBz68MMP1axZM0MVAbAbdir2FijjURfmj+3bt+vLL78sdxPGadOm+amqin377beaPHmypk2bppSUlDKba0VHR1cp9z//+Y9mzJih559/vsw36LAPU8uHHe3YsUNDhgzRtm3blJiYKEnKzc1VcnKy3n///Vr1/nzqJplnqkOHDgoOrtq6HdYInSIzM1MTJkxQVFTUaR9rWZYee+wxFRUV1UBlAOzi5E7FtWli8adAGQ+7zx9z5szR7bffroYNGyo+Pt5rzZ3D4aiVjVBsbKwKCgp04YUXet1e3c21rrvuOh05ckRdunRRaGiowsPDve4/cOBAlWu2q/T0dDVp0kQ33nij1+2vvPKKfv31V917771+qqxippYPO2rdurU2btyozz77TN9//70kqX379ho4cGCtW0vftWvXP9wk8/ecTqe2bdumVq1aVen5WCN0CqfTqb1796px48Zn9Ph69eppw4YNVR58AHXDqd9gZWdn6/7779c///lP2+xU7GuBOB52nz9atGihO+64o1Z+oK1I9+7dFRwcrDFjxpS7M3y/fv2qlDt//vw/vP/666+vUq6dJSUl6Y033lDv3r29bl+1apWuueaaWrkZnanlA2Y5nU6tXr1ajRo1Ou1jLctSSkqKNm7cSCPkCz/88IOaN29+xt1xbm6umjZtqqCgIMOVAajN7L5Tsa8F4njYff6Ijo5WZmZmrWnMzkRERITWr1+vtm3b+ruUOi8sLExbtmxRy5YtvW7fuXOnOnTooGPHjvmpsoqxfHhbsmSJlixZUu6mr6+88oqfqiprwIABeu+99xQbG3tGj7/00kv18ssvKyEhoUrPx6Zxp2jRokWlHn9yO0sAga02fhvqT4E4HnafP4YNG6ZPP/1Uo0eP9ncpZ6xbt27Kzc018kE3Oztbc+fOVXZ2tmbPnq3GjRvrk08+UfPmzdWxY0efP19tl5iYqG+++aZMI/TNN9+oadOmfqrqj5lcPuwmLS1NDz30kLp161brD1rz5ZdfVurxH3/8cbWej0bod/bv36/Dhw97TWqbN2/WE088ocOHD+vKK6/UP/7xDz9WCKC2qeyH4LouUMfDzvNH69atNXXqVK1cubLcTRjvueceP1VWsbvvvltjxozx+WaXS5cu1SWXXKLzzz9fX331lR599FE1btxYGzZs0Msvv6y3337bF+Xbyi233KKxY8fq+PHjnn1ulixZokmTJmnChAl+rq58ppYPO3rhhRc0b948jRw50t+lVEtJSYmOHTt2Rvtinik2jfud4cOHq2nTpnryySclSfv27VO7du3UtGlTnX322frkk0/08ssv235hAmCGHXcqNimQxsPO88fvv+k/lcPh0M6dO2uwmjPjdDrL3OaLzS579eqlYcOGafz48V77cq1evVpXXXWVfvzxx+qWbjuWZWny5Ml6+umnVVxcLOnE5nL33ntvrTyQhmRu+bCjuLg4rV69Wmeffba/Szkj//nPf5SXl6dRo0Z5bnv00Uf18MMPq6SkRBdeeKHefPNN1a9fv9rPRSP0Oy1bttS8efM8O9E98cQTeuGFF/T9998rODhYTzzxhN5++22tXLnSz5UCqI3suFOxSYE0HswfNeuHH374w/urumYyKipKmzZtUsuWLb0aod27d6tdu3a1cn+YmlJYWKgtW7YoPDxcycnJcrlc/i6pQqaWDzu69957FRUVpalTp/q7lDMyYMAA/e1vf9Odd94pSVq+fLn69u2rhx56SO3bt9eUKVN0ySWX6Kmnnqr2c7Fp3O/s3btXSUlJnutffPGFrrrqKs/xyf/6178qPT3dT9UBqO327t1b7k6bjRo10p49e/xQkX8F0ngwf9QsUx9kY2NjtWfPnjJrydavX1+rzvvkD1FRUTrvvPP8XcYZCaRG53SOHTumF198UZ9//rk6d+5cZjNBXzQUvrR582avmt5++239+c9/1pQpUySdWBs5ZswYGiEToqOjdfDgQc8LaPXq1brppps89zscjlp17odTlZaWat68eRUeFeSLL76ocvbBgwe1evXqcnOvu+66KucCdY3JnYrt+Dq0407WVcX8UfNee+01vfDCC9q1a5dWrFihFi1aaNasWWrZsqWuuOKKKmVec801uvfee/V///d/cjgccrvd+uabbzRx4sRa+zoz4aqrrjrjx7777rsGK6k6E8uHHW3cuFFdu3aVJH333Xde99XGAyccOnRIcXFxnuvLli3TsGHDPNc7duyon3/+2SfPRSP0Oz179tTTTz+tOXPm6N1339WhQ4e8TsZ16ll5a5sxY8Zo3rx5uuyyy5SSkuKzhfs///mPRowYocLCQkVHR5c50V4gTQzA6Zjaqdiur0M77mRdVcwfNev555/XtGnTNHbsWD366KOefT5iY2M1a9asKn/QnT59uu68804lJiaqtLRUHTp0UGlpqf7xj3/o/vvv9+WfUKvFxMR4frYsS++9955iYmLUrVs3SdLatWt18ODBSjVMNcnU8mFHlT0Sm781a9ZMW7ZsUfPmzVVYWKgNGzZo5syZnvvz8vIUERHhmyez4GXDhg1Ww4YNrdDQUMvpdFr333+/1/3XXnutddttt/mpuj8WFxdnffTRRz7PTU5OtsaMGWMdPnzY59lAXeN2u61JkyZZYWFhltPptJxOpxUREWGlpaVVK9eur0NT41EbMX/UrPbt21vvvfeeZVmWFRUVZWVnZ1uWZVmbNm2y4uLiqp3/ww8/WB999JH15ptvWtu2bat2np1NmjTJuvnmm62SkhLPbSUlJdatt95qTZw40Y+VVcz08gFzJk+ebLVr18569dVXrWuuucZq3ry517L373//2zr//PN98lwcLKEc+/fv1zfffKP4+Hj16NHD676PPvpIHTp0+MMj7PhL06ZNlZGRoTZt2vg0NzIyUps2bbLVifYAf/P1TsV2fx3aaSfr6mD+qDnh4eH6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7u/yKtSyZUtr3bp1lmVZ1rnnnmu98MILlmVZ1uLFi6u1k928efOso0eP+qRGfzl69KjnSDfVPeLNihUrrJYtW3qWi1MvtXnnzlP5cjxM2rZtm9WnTx/P6/DU12NtHusdO3ZYU6ZMsa655hrPDrUff/yx9d1331U5086vQxPjUVuZnD8WL15s/eUvf/EcfMKXfD1/nPqe8vv3Gl+995gaj//+97/WoEGDjIyzZVnWb7/9Zi1evNh67bXXrPnz53tdqsPX49GyZUtr//79lmWdOJKer5aPmlg2TtZm6vWydOnSP7xU1bZt26xu3br5fM578803rVatWlnPPPOMtXz5cmvDhg1el9rm6NGjVu/eva2goCDr4osvtsaNG2eNHTvWGjRokBUUFGT16tXLZ/Mhm8b9gczMTK+TOJnYHMGXbr75ZiUmJuqBBx7Qc889p3/+8586//zztWbNGl111VV6+eWX/V1ijTpy5IgmTZqkt956S3l5eWXur+qOo127dlWbNm2UlpZW7nbHtXV/DVPjYdL555+v4OBgTZ48udyx9uV21L6ydOlSXXLJJTr//PP11VdfacuWLWrVqpUee+wxrVmzRm+//ba/S6xRgToeJuaP+vXr68iRIyopKVFERESZb4sPHDhQ5Wxfzx9BQUHas2ePGjduLKfTWe4359b/2++tqu89psbD5Dj/5z//0YgRI1RYWKjo6GivcXE4HNXK9nXds2fP1m233aawsDDdeOONatmypaZOnVrt5aMmlg3J7P9jeed4+/1+TlXRvXt3BQcHa8yYMeXun3ZyjVRlVVSvL8bZlOLi4nJPTn3NNddo3LhxcrlcPnkeGqEzVFxcrOLiYq/NUmobt9stt9vt2YfgzTff1DfffKPk5GSNHj26UqueGzRooG3btqlhw4aenRorUp03E5PuvPNOffnll3r44Yc1cuRIPffcc/rpp5/073//W4899phGjBhRpdzIyEht2LBBrVu39nHFZpkaD5MiIyO1du1atWvXzt+lnLFevXpp2LBhGj9+vNe29KtXr9ZVV12lH3/88Yyz6sLr0JfjYVe+mj/mz5//h/dX52Scvpw/pBMN8MkvMk49oWh5qvrhztR4mBznNm3a6NJLL9X06dMVERFR5ZzymKy7uLjY01BI1Vs+amLZkMyOR35+vtf148ePa/369Zo6daoeffTRKh8IJiIiQuvXr1fbtm2rXFt5fvjhhz+83y6bzJlAI1SOuXPnat26derZs6dGjBih++67T08++aRKSkp04YUXauHChYqLi/N3meU6duyYNm7cWGZ/CofDocsvv/yMc+bPn69rrrlGLpfL6JuJSc2bN9err76q/v37Kzo6WuvWrVPr1q312muvacGCBfr444+rlHvhhRdq0qRJuvjii31csVmmxsOk8847TzNnzjS207IJUVFR2rRpk1q2bOn1wX/37t1q166d5xCmZ6IuvA59OR52wPxRuWxJ+utf/1qtbDuJjIzUpk2b1KpVK3+XUmmmlo+6tGwsXbpU48eP19q1a6v0+xdccIGmTZumgQMH+rSur776Sr179/Y62I504ohyy5cvr3X7Nq9evVrnnnuugoKCyr2/qKhIH3zwgf7+979X/8l8soFdHfLII49Y4eHh1sCBA60GDRpYo0ePtuLj463HHnvMmjFjhnXWWWdZo0eP9neZ5frkk0+shg0bltlvpbrblo4cOdJ6+eWXrR07dviwWvMiIyOtH374wbKsE2dVXrVqlWVZlrVz504rMjKyyrnvvvuu1aFDB2vu3LnWmjVrav22tieZGg+TlixZYvXq1cv68ssvrf3799tiv6ZmzZpZ33zzjWVZlhUVFWVlZ2dblnViuWnVqlWVc+36OjQ1HrWRifmjpvanMDV/nMxu1KiRT7JNjUdNjfOQIUOsN998s1oZp6rJ5cNX/4cmc2tqPCqyZcuWas2nb731lpHPF3Y7ce3v661Xr55n7rAsy9q7d6/P6qYR+p3WrVtbb7zxhmVZlvXtt99aTqfT60zhH3/8sdW8eXN/lfeHWrdubd1xxx3W3r17fZp78803W8nJyZbT6bTOOussa8SIEdacOXPKPTt2bdKpUycrIyPDsizLuuiii6wJEyZYlmVZs2fPtpo1a1bl3PLesO1wsART42HS78fWDgdLmDBhgtWnTx9rz549Vr169azt27dby5Yts1q1amU9+OCDVc616+vQ1HjURibmj1M/EPz+deDL14Op+cPX2abGo6bG+aWXXrKaN29uPfDAA9bbb79tffDBB16XyrL78uHr3Joaj983KJmZmdYnn3xi9evXzzr//POrnGvq84XD4bD27dtX5vatW7da9erVq3KuKQ6Hw6sROvVLNMs60Qg5HA7fPJdlsWncqVwul3bs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Oy4fJpc70+Nhp88XR44c8eR++umnuuqqq+R0OtWzZ8/THqChptXEe+mpfL/k2dg555yjvLy8M358r169lJOTU6nnSElJ0YYNGyRJPXr00IwZM/TNN9/ooYceqvYL8/rrr9ebb75ZrYzyWJaldevW6amnntJf//pXDRgwQP/7v/+rTp06VWv7XcnseNx888164403qpVRHpM123E87rjjDq1cuVKvvPKKli9f7nnzatWqlR599NFqZV999dW66aab9Oabbyo3N1e5ublauHChbr75Zg0fPrzKuSbHeeTIkXr++efL3P7iiy9qxIgRVc616+vQ1HjUNjUxf9xyyy0aM2aMVq1aJYfDoZ9//lmvv/66Jk6cqNtvv72yJXsxNX+YzDY1HibHuSL5+fnKz8+vVoYdlw+Ty53J8bDb54vWrVvr/fffV25urhYvXqy//OUvkqR9+/YpOjraJ7X7Sk28l56KNUKnsCxLU6dO9exMdjpVOYT2/fffr8OHD0s6sdPk4MGD1bdvX8XFxVX7zaC0tFQzZszQ4sWL1blz5zI7HT711FNVym3QoIEKCwvVpUsX9evXT7fccov69u2r2NjYatUr+X48xo8f7/nZ7XbrxRdf1Oeff+7T8TD5f2iX8Rg/frwefvhhRUZGej3H119/Xeax1fnW7IknnpDD4dB1113nWXsQEhKi22+/XY899liVc02Os8Ph0EsvvaRPP/1UPXv2lCStWrVKOTk5uu6666pcs11fh6bG448MHDhQO3fu1M6dO43kl6cm5o/JkyfL7Xbroosu0pEjR3TBBRfI5XJp4sSJuvvuuyuddypT84fJbFPjYXKcn376aa/rlmVpz549eu2113TJJZdUK9uOy4fJ5c7X42HnzxfTpk3TP/7xD40bN04XXXSRevXqJenE2qFzzjmnyrmnU5X34pp4Lz0V5xE6Rf/+/T1H5jhTb7zxhhISEqr1vAcOHFD9+vUr/dy/N2DAgArvczgc+uKLL6qU+9FHH6lv37419q1Bdcbjj8bgVNUZj/L46v/Q19mmxmPAgAF67733FBsba2y5O9WRI0eUnZ0tSTr77LPP+A2yMmrjOJ+K1+GZe+6557R//3498MADPs+uSE3OH8XFxdqxY4cKCwvVoUMHRUVFVTrj90y+jk2/R5gYD1O5vz9s88nDLl944YVKTU2t1ia/J9lp+aiJ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fL/vlz1H8bEzfixrhAAAAAAEHBohAAAAAAGHRggAAABAwKERAgAAABBwaIQAAAAABBwaIQAAAAABp8qNUP/+/eVwOORwOJSZmenDkuxVAwAAAAD7qdYaoVtuuUV79uxRSkqKdu/e7WlKfn9ZuXKl53eOHj2qBx54QG3atJHL5VLDhg01bNgwbd682Sv7yJEjSk1N1dlnn62wsDA1atRI/fr10wcffOB5zLvvvqvVq1dX508AAAAAEICqdULViIgIxcfHe932+eefq2NH7zPVxcXFSZKKioo0cOBA5eTk6Mknn1SPHj30yy+/KD09XT169NDnn3+unj17SpJGjx6tVatW6ZlnnlGHDh2Ul5en5cuXKy8vz5PboEEDFZg8aSIAAACAOqlajVB54uLiyjRHJ82aNUsrVqzQ+vXr1aVLF0lSixYt9M4776hHjx666aab9N1338nhcOjDDz/U7Nmzdemll0qSkpKSdO655/q6XAAAAAABqEYPlvDGG2/oz3/+s6cJ8hThdGrcuHHKysrShg0bJEnx8fH6+OOPdejQoWo/b1FRkQoKCrwuAACcDvMHANRdPm+EevfuraioKK/LSdu2bVP79u3L/b2Tt2/btk2S9OKLL2r58uWKi4vTeeedp3Hjxumbb76pUk3p6emKiYnxXBITE6uUAwAILMwfAFB3+bwRevPNN5WZmel1OZVlWWeUc8EFF2jnzp1asmSJ/va3v2nz5s3q27evHn744UrXlJqaqvz8fM8lNze30hkAgMDD/AEAdZfP9xFKTExU69aty72vTZs22rJlS7n3nby9TZs2nttCQkLUt29f9e3bV/fee68eeeQRPfTQQ7r33nsVGhp6xjW5XC65XK5K/BUAADB/AEBdVqP7CF1zzTX6/PPPPfsBneR2uzVz5kx16NChzP5Dp+rQoYNKSkp07Ngx06UCAAAAqMN8vkYoLy9Pe/fu9botNjZWYWFhGjdunD744ANdfvnlXofPnj59urZs2aLPP/9cDodD0omTpQ4fPlzdunVTXFycsrKydN9992nAgAGKjo72ddkAAAAAAojPG6GBAweWuW3BggW65pprFBYWpi+++ELTp0/Xfffdpx9++EH16tXTgAEDtHLlSqWkpHh+Z9CgQZo/f77uu+8+HTlyRE2bNtXgwYM1bdo0X5cMAAAAIMD4rBFKSko6owMhRERE6JFHHtEjjzzyh49LTU1Vamqqr8oDAAAAAI9q7SP0r3/9S1FRUdq0aZOv6qmUSy65RB07dvTLcwMAAACwryqvEXr99dd19OhRSVLz5s19VlBlvPTSS36vAQAAAID9VLkRatasmS/rsG0NAAAAAOzH5wdLsIOT+zKVWMcNPUGpmVw5DOUadoYn0QVsw3IbyjX13mGYofEoPGQot/BE7pme4PtUJ3/HfbTIpzV5BJn5m92l5s6WcaywxFi229DpMiyTJw85Yu4UH+5jhgo39JYmSaUGx6O0OMRcdpGZz1wlxw199pRUUmrofUlSaZGZ/8fSYt9/RiwtPlHrmbzHO6yqzAQ29+OPPyoxMdHfZQAA/Cg3N1dnnXVWpX6H+QMA7OFM3uMDshFyu936+eefVa9ePc95iypSUFCgxMRE5ebm+vz8RXbMtmPNJrPtWLPJbDvWbDKbmmtntmVZOnTokJo2bSqns3LfsDN/1L5cu2ZTs/2z7VizyezaUnNl3uMDctM4p9NZ6W8Bo6OjjZ3I1Y7ZdqzZZLYdazaZbceaTWZTc+3LjomJqVI+80ftzbVrNjXbP9uONZvMrg01n+l7vMmtZAEAAACgVqIRAgAAABBwaIROw+Vy6YEHHpDL5SLbYK5ds+1Ys8lsO9ZsMpua60Z2Vdn172XZqplsarZ/th1rNpltx5oD8mAJAAAAAAIba4QAAAAABBwaIQAAAAABh0YIAAAAQMChEQIAAAAQcGiEAAAAAAQcGiEAAAAAAYdGCAAAAEDAoRECAAAAEHD+Pwls7tAtjZp4AAAAAElFTkSuQmCC",
            "text/plain": [
              "<Figure size 1000x500 with 2 Axes>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "data": {
            "text/plain": [
              "['a man with a hat and a hat is on a beach with a beach.']"
            ]
          },
          "execution_count": 67,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "\n",
        "# 在 Windows 系统上并没有 sys/mman.h 文件，windows上无法安装fastBPE\n",
        "import re\n",
        "from fastBPE import fastBPE\n",
        "from sacremoses import MosesDetokenizer, MosesTokenizer\n",
        "\n",
        "# `MosesTokenizer` 和 `MosesDetokenizer` 是来自 `sacremoses` 库的工具，用于自然语言处理中的分词（Tokenization）和去标记化（Detokenization）。这些工具主要用于对文本进行预处理和后处理，通常在处理自然语言处理任务时会用到。\n",
        "#\n",
        "# ### MosesTokenizer：\n",
        "# - **作用**：将原始文本分割成单词和标点符号。\n",
        "# - **特点**：基于 Moses 翻译工具中使用的分词方法。\n",
        "# - **功能**：\n",
        "#   - 将句子分割成单词和标点符号。\n",
        "#   - 处理缩写、连字符、标点等特殊情况。\n",
        "#   - 对文本进行标记化，方便后续处理。\n",
        "#\n",
        "# ### MosesDetokenizer：\n",
        "# - **作用**：将分词后的文本重新组合成原始的句子。\n",
        "# - **特点**：用于对分词后的文本进行还原，使其恢复为可读的句子形式。\n",
        "# - **功能**：\n",
        "#   - 将分词后的单词和标点符号重新组合成句子。\n",
        "#   - 处理分词后的标点、缩写等情况，使得结果更加自然和可读。\n",
        "#\n",
        "# 这些工具通常在文本预处理和后处理过程中使用，对输入的文本进行标记化和去标记化，是一种常用的处理方式。在自然语言处理任务中，对文本进行正确的分词和还原是很重要的，而 `MosesTokenizer` 和 `MosesDetokenizer` 提供了方便、高效的工具来处理这些任务。\n",
        "\n",
        "class Translator:\n",
        "    def __init__(self, model, src_tokenizer, trg_tokenizer):\n",
        "        self.bpe = fastBPE(\"./wmt16/bpe.20000\", \"./wmt16/vocab\") #如果bpe.20000名字变了，这里要改\n",
        "        self.mose_tokenizer = MosesTokenizer(lang=\"de\") # 德语分词器，如果是其他语言，这里要改\n",
        "        self.mose_detokenizer = MosesDetokenizer(lang=\"en\") # 英语去标记化器，如果是其他语言，这里要改\n",
        "        self.model = model # 模型\n",
        "        self.model.eval() # 设置为评估模式\n",
        "        self.src_tokenizer = src_tokenizer # 源语言分词器\n",
        "        self.trg_tokenizer = trg_tokenizer # 目标语言分词器\n",
        "        # 使用正则表达式编译器创建一个模式对象，用于匹配分词器fastBPE在分词后添加的特殊标记“@@ ”或“@@”出现在字符串末尾（可选后跟一个空格）\n",
        "        # 具体来说，'(@@ )' 匹配所有以“@@ ”结尾的子词标记（即“@@”后跟一个空格），\n",
        "        # '(@@ ?$)' 匹配所有以“@@”结尾且可能后面有一个空格的子词标记（“?”表示空格出现0次或1次，\"$\"表示字符串结尾）。\n",
        "        # 这样可以在后处理时将这些BPE分词标记去除，恢复为完整的单词。\n",
        "        self.pattern = re.compile(r'(@@ )|(@@ ?$)')  \n",
        "\n",
        "    def draw_attention_map(self, attn_scores, cross_attn_scores, src_words_list, trg_words_list):\n",
        "        \"\"\"绘制注意力热力图\n",
        "        attn_scores (numpy.ndarray): 表示自注意力机制（self-attention）分数。\n",
        "        cross_attn_scores (numpy.ndarray): 表示交叉注意力机制的注意力分数。\n",
        "        src_words_list (list): 源语言句子的单词列表。\n",
        "        trg_words_list (list): 目标语言句子的单词列表。\n",
        "        \"\"\"\n",
        "        assert len(attn_scores.shape) == 3, \"attn_scores shape should be \" \\\n",
        "            f\"[num heads, target sequence length, target sequence length], but got {attn_scores.shape}\"\n",
        "        attn_scores = attn_scores[:, :len(trg_words_list), :len(trg_words_list)]\n",
        "\n",
        "        assert len(cross_attn_scores.shape) == 3, \"attn_scores shape should be \" \\\n",
        "            f\"[num heads, target sequence length, source sequence length], but got {cross_attn_scores.shape}\"\n",
        "        cross_attn_scores = cross_attn_scores[:, :len(trg_words_list), :len(src_words_list)]\n",
        "\n",
        "        num_heads, trg_len, src_len = cross_attn_scores.shape\n",
        "\n",
        "        fig = plt.figure(figsize=(10, 5), constrained_layout=True) # constrained_layout=True 自动调整子图参数，使之填充整个图像区域\n",
        "        grid = plt.GridSpec(trg_len, trg_len + src_len, wspace=0.1, hspace=0.1)# wspace,hspace 控制子图之间的间距\n",
        "        #下面是attn_scores的热力图\n",
        "        self_map = fig.add_subplot(grid[:,:trg_len]) #  添加子图\n",
        "        self_map.matshow(attn_scores.mean(dim=0), cmap='viridis') # 绘制热力图，cmap表示颜色,dim=0表示对第0维求均值\n",
        "        self_map.set_yticks(range(trg_len), trg_words_list, fontsize=10)\n",
        "        self_map.set_xticks(range(trg_len), [\"[BOS]\"] + trg_words_list[:-1], rotation=90)\n",
        "        #下面是cross_attn_scores的热力图\n",
        "        cross_map = fig.add_subplot(grid[:, trg_len:])\n",
        "        cross_map.matshow(cross_attn_scores.mean(dim=0), cmap='viridis')\n",
        "        cross_map.set_yticks(range(trg_len), [], fontsize=6)\n",
        "        cross_map.set_xticks(range(src_len), src_words_list, rotation=90)\n",
        "\n",
        "        plt.show()\n",
        "\n",
        "    def draw_attention_maps(self, attn_scores, cross_attn_scores, src_words_list, trg_words_list, heads_list):\n",
        "        \"\"\"绘制注意力热力图\n",
        "\n",
        "        Args:\n",
        "            - scores (numpy.ndarray): shape = [source sequence length, target sequence length]\n",
        "        \"\"\"\n",
        "        assert len(attn_scores.shape) == 3, \"attn_scores shape should be \" \\\n",
        "            f\"[num heads, target sequence length, target sequence length], but got {attn_scores.shape}\"\n",
        "        attn_scores = attn_scores[:, :len(trg_words_list), :len(trg_words_list)]\n",
        "\n",
        "        assert len(cross_attn_scores.shape) == 3, \"attn_scores shape should be \" \\\n",
        "            f\"[num heads, target sequence length, source sequence length], but got {cross_attn_scores.shape}\"\n",
        "        cross_attn_scores = cross_attn_scores[:, :len(trg_words_list), :len(src_words_list)]\n",
        "        # cross_attn_scores = cross_attn_scores[:, :len(src_words_list), :len(src_words_list)]\n",
        "\n",
        "        num_heads, trg_len, src_len = cross_attn_scores.shape\n",
        "        fig, axes = plt.subplots(2, len(heads_list), figsize=(5 * len(heads_list), 10))\n",
        "        for i, heads_idx in enumerate(heads_list):\n",
        "            axes[0, i].matshow(attn_scores[heads_idx], cmap='viridis')\n",
        "            axes[0, i].set_yticks(range(trg_len), trg_words_list)\n",
        "            axes[0, i].set_xticks(range(trg_len), [\"[BOS]\"] + trg_words_list[:-1], rotation=90)\n",
        "            axes[0, i].set_title(f\"head {heads_idx}\")\n",
        "            axes[1, i].matshow(cross_attn_scores[heads_idx], cmap='viridis')\n",
        "            axes[1, i].set_yticks(range(trg_len), trg_words_list)\n",
        "            axes[1, i].set_xticks(range(src_len), src_words_list, rotation=90)\n",
        "            axes[1, i].set_title(f\"head {heads_idx}\")\n",
        "\n",
        "        plt.show()\n",
        "\n",
        "\n",
        "    def __call__(self, sentence_list, heads_list=None, layer_idx=-1):\n",
        "        # 将输入句子列表转换为小写，并使用 MosesTokenizer 进行分词处理。\n",
        "        sentence_list = [\" \".join(self.mose_tokenizer.tokenize(s.lower())) for s in sentence_list]\n",
        "        # 将分词后的结果进行 BPE 编码，得到 tokens_list。\n",
        "        tokens_list = [s.split() for s in self.bpe.apply(sentence_list)]\n",
        "        print(tokens_list)\n",
        "        # 使用 src_tokenizer 对 tokens_list 进行编码，同时添加起始标记 ([BOS]) 和结束标记 ([EOS])。\n",
        "        encoder_input, attn_mask = self.src_tokenizer.encode(\n",
        "            tokens_list,\n",
        "            add_bos=True,\n",
        "            add_eos=True,\n",
        "            return_mask=True,\n",
        "            )\n",
        "        encoder_input = torch.Tensor(encoder_input).to(dtype=torch.int64)\n",
        "        # 使用模型的 infer 方法对编码器输入进行推理，得到输出结果 outputs\n",
        "        outputs = model.infer(encoder_inputs=encoder_input, encoder_inputs_mask=attn_mask)\n",
        "\n",
        "        preds = outputs.preds.numpy()\n",
        "        # 使用目标语言的 trg_tokenizer 对预测序列进行解码，得到解码后的目标语言句子列表 trg_decoded。\n",
        "        trg_decoded = self.trg_tokenizer.decode(preds, split=True, remove_eos=False, remove_bos=False, remove_pad=False)\n",
        "        # 使用源语言的 src_tokenizer 对编码器输入进行解码，得到解码后的源语言句子列表 src_decoded。为下面绘制热力图做准备。\n",
        "        src_decoded = self.src_tokenizer.decode(\n",
        "            encoder_input.numpy(),\n",
        "            split=True,\n",
        "            remove_bos=False,\n",
        "            remove_eos=False\n",
        "            )\n",
        "\n",
        "        # post processed attn scores\n",
        "        # outputs.decoder_attentions[-1]  # the last layer of self-attention scores\n",
        "\n",
        "        # draw the attention map of the last decoder block\n",
        "        for attn_score, cross_attn_score, src, trg in zip(\n",
        "            outputs.decoder_attentions[layer_idx], outputs.cross_attentions[layer_idx], src_decoded, trg_decoded):\n",
        "            if heads_list is None:# 如果没有指定heads_list，就画单个热力图\n",
        "                self.draw_attention_map(\n",
        "                    attn_score,\n",
        "                    cross_attn_score,\n",
        "                    src,\n",
        "                    trg,\n",
        "                )\n",
        "            else:# 如果指定了heads_list，就画多个热力图\n",
        "                self.draw_attention_maps(\n",
        "                    attn_score,\n",
        "                    cross_attn_score,\n",
        "                    src,\n",
        "                    trg,\n",
        "                    heads_list=heads_list,\n",
        "                    )\n",
        "        return [self.mose_detokenizer.tokenize(self.pattern.sub(\"\", s).split()) for s in self.trg_tokenizer.decode(preds)] #将解码后的目标语言句子列表返回，并使用 mose_detokenizer 进行去标记化，最终得到翻译后的结果。\n",
        "\n",
        "\n",
        "# sentence_list = [\n",
        "#     \"Mann in einem kleinen weißen Boot auf einem See.\",  # Man in a small white boat on a lake.\n",
        "#     \"Ein Mann mit einem Eimer und ein Mädchen mit einem Hut am Strand.\", # A man with a bucket and a girl in a hat on the beach.\n",
        "#     \"Drei Männer auf Pferden während eines Rennens.\",  # Three men on horses during a race.\n",
        "#     \"Ein Mann und eine Frau essen zu Abend\",  # 一个男人和一个女人在吃晚餐\n",
        "# ]\n",
        "sentence_list = [\n",
        "    # \"Mann in einem kleinen weißen Boot auf einem See.\",  # Man in a small white boat on a lake.\n",
        "    \"Ein Mann mit einem Eimer und ein Mädchen mit einem Hut am Strand.\", # A man with a bucket and a girl in a hat on the beach.\n",
        "    # \"Drei Männer auf Pferden während eines Rennens.\",  # Three men on horses during a race.\n",
        "    # \"Ein Mann und eine Frau essen zu Abend\",  # 一个男人和一个女人在吃晚餐\n",
        "]\n",
        "\n",
        "# load checkpoints\n",
        "model = TransformerModel(config)\n",
        "model.load_state_dict(state_dict)\n",
        "translator = Translator(model.cpu(), tokenizer, tokenizer)\n",
        "translator(\n",
        "    sentence_list,\n",
        "    layer_idx=-1,\n",
        "    # heads_list=[0, 1, 2, 3, 4, 5, 6, 7]\n",
        "    )\n"
      ]
    }
  ],
  "metadata": {
    "accelerator": "GPU",
    "colab": {
      "gpuType": "L4",
      "machine_shape": "hm",
      "provenance": []
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.12.3"
    },
    "widgets": {
      "application/vnd.jupyter.widget-state+json": {
        "046c17ba17f94587968cda8c761c2bf7": {
          "model_module": "@jupyter-widgets/base",
          "model_module_version": "1.2.0",
          "model_name": "LayoutModel",
          "state": {
            "_model_module": "@jupyter-widgets/base",
            "_model_module_version": "1.2.0",
            "_model_name": "LayoutModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "LayoutView",
            "align_content": null,
            "align_items": null,
            "align_self": null,
            "border": null,
            "bottom": null,
            "display": null,
            "flex": null,
            "flex_flow": null,
            "grid_area": null,
            "grid_auto_columns": null,
            "grid_auto_flow": null,
            "grid_auto_rows": null,
            "grid_column": null,
            "grid_gap": null,
            "grid_row": null,
            "grid_template_areas": null,
            "grid_template_columns": null,
            "grid_template_rows": null,
            "height": null,
            "justify_content": null,
            "justify_items": null,
            "left": null,
            "margin": null,
            "max_height": null,
            "max_width": null,
            "min_height": null,
            "min_width": null,
            "object_fit": null,
            "object_position": null,
            "order": null,
            "overflow": null,
            "overflow_x": null,
            "overflow_y": null,
            "padding": null,
            "right": null,
            "top": null,
            "visibility": null,
            "width": null
          }
        },
        "110a1f620812433692b0442ba588013c": {
          "model_module": "@jupyter-widgets/base",
          "model_module_version": "1.2.0",
          "model_name": "LayoutModel",
          "state": {
            "_model_module": "@jupyter-widgets/base",
            "_model_module_version": "1.2.0",
            "_model_name": "LayoutModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "LayoutView",
            "align_content": null,
            "align_items": null,
            "align_self": null,
            "border": null,
            "bottom": null,
            "display": null,
            "flex": null,
            "flex_flow": null,
            "grid_area": null,
            "grid_auto_columns": null,
            "grid_auto_flow": null,
            "grid_auto_rows": null,
            "grid_column": null,
            "grid_gap": null,
            "grid_row": null,
            "grid_template_areas": null,
            "grid_template_columns": null,
            "grid_template_rows": null,
            "height": null,
            "justify_content": null,
            "justify_items": null,
            "left": null,
            "margin": null,
            "max_height": null,
            "max_width": null,
            "min_height": null,
            "min_width": null,
            "object_fit": null,
            "object_position": null,
            "order": null,
            "overflow": null,
            "overflow_x": null,
            "overflow_y": null,
            "padding": null,
            "right": null,
            "top": null,
            "visibility": null,
            "width": null
          }
        },
        "114607d303c64d558617e41975b25270": {
          "model_module": "@jupyter-widgets/base",
          "model_module_version": "1.2.0",
          "model_name": "LayoutModel",
          "state": {
            "_model_module": "@jupyter-widgets/base",
            "_model_module_version": "1.2.0",
            "_model_name": "LayoutModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "LayoutView",
            "align_content": null,
            "align_items": null,
            "align_self": null,
            "border": null,
            "bottom": null,
            "display": null,
            "flex": null,
            "flex_flow": null,
            "grid_area": null,
            "grid_auto_columns": null,
            "grid_auto_flow": null,
            "grid_auto_rows": null,
            "grid_column": null,
            "grid_gap": null,
            "grid_row": null,
            "grid_template_areas": null,
            "grid_template_columns": null,
            "grid_template_rows": null,
            "height": null,
            "justify_content": null,
            "justify_items": null,
            "left": null,
            "margin": null,
            "max_height": null,
            "max_width": null,
            "min_height": null,
            "min_width": null,
            "object_fit": null,
            "object_position": null,
            "order": null,
            "overflow": null,
            "overflow_x": null,
            "overflow_y": null,
            "padding": null,
            "right": null,
            "top": null,
            "visibility": null,
            "width": null
          }
        },
        "16ae7acad596458890f112a68c515cdf": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "HTMLModel",
          "state": {
            "_dom_classes": [],
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "HTMLModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/controls",
            "_view_module_version": "1.5.0",
            "_view_name": "HTMLView",
            "description": "",
            "description_tooltip": null,
            "layout": "IPY_MODEL_ec9417d5c4e54d18966e0140e60e4f7e",
            "placeholder": "​",
            "style": "IPY_MODEL_2d5c3abf516b48b6946778709ac9d97d",
            "value": " 16/128 [00:00&lt;00:01, 68.16it/s]"
          }
        },
        "17b7154badac4cae83ae11e0bbc8f881": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "DescriptionStyleModel",
          "state": {
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "DescriptionStyleModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "StyleView",
            "description_width": ""
          }
        },
        "260f33f2bfc745cf904790692b45daa3": {
          "model_module": "@jupyter-widgets/base",
          "model_module_version": "1.2.0",
          "model_name": "LayoutModel",
          "state": {
            "_model_module": "@jupyter-widgets/base",
            "_model_module_version": "1.2.0",
            "_model_name": "LayoutModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "LayoutView",
            "align_content": null,
            "align_items": null,
            "align_self": null,
            "border": null,
            "bottom": null,
            "display": null,
            "flex": null,
            "flex_flow": null,
            "grid_area": null,
            "grid_auto_columns": null,
            "grid_auto_flow": null,
            "grid_auto_rows": null,
            "grid_column": null,
            "grid_gap": null,
            "grid_row": null,
            "grid_template_areas": null,
            "grid_template_columns": null,
            "grid_template_rows": null,
            "height": null,
            "justify_content": null,
            "justify_items": null,
            "left": null,
            "margin": null,
            "max_height": null,
            "max_width": null,
            "min_height": null,
            "min_width": null,
            "object_fit": null,
            "object_position": null,
            "order": null,
            "overflow": null,
            "overflow_x": null,
            "overflow_y": null,
            "padding": null,
            "right": null,
            "top": null,
            "visibility": null,
            "width": null
          }
        },
        "280b011dc683465985da449bc80ab71f": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "FloatProgressModel",
          "state": {
            "_dom_classes": [],
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "FloatProgressModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/controls",
            "_view_module_version": "1.5.0",
            "_view_name": "ProgressView",
            "bar_style": "danger",
            "description": "",
            "description_tooltip": null,
            "layout": "IPY_MODEL_046c17ba17f94587968cda8c761c2bf7",
            "max": 128,
            "min": 0,
            "orientation": "horizontal",
            "style": "IPY_MODEL_79a55387adba484e9485779a07bcc8e9",
            "value": 16
          }
        },
        "2d5c3abf516b48b6946778709ac9d97d": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "DescriptionStyleModel",
          "state": {
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "DescriptionStyleModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "StyleView",
            "description_width": ""
          }
        },
        "3212f3a98f5e4a96ac888f368f4fff42": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "HBoxModel",
          "state": {
            "_dom_classes": [],
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "HBoxModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/controls",
            "_view_module_version": "1.5.0",
            "_view_name": "HBoxView",
            "box_style": "",
            "children": [
              "IPY_MODEL_8af2647d8486443a8a025bc30e9ddac6",
              "IPY_MODEL_280b011dc683465985da449bc80ab71f",
              "IPY_MODEL_16ae7acad596458890f112a68c515cdf"
            ],
            "layout": "IPY_MODEL_f6971c6f2b22427cb2b58ffffda71135"
          }
        },
        "32ab830293104d33b6f584b0ed030aeb": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "DescriptionStyleModel",
          "state": {
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "DescriptionStyleModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "StyleView",
            "description_width": ""
          }
        },
        "381277e910d647b98475c7e514d4ce59": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "HBoxModel",
          "state": {
            "_dom_classes": [],
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "HBoxModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/controls",
            "_view_module_version": "1.5.0",
            "_view_name": "HBoxView",
            "box_style": "",
            "children": [
              "IPY_MODEL_79e7a2f67e704862b46c4479a28aa57e",
              "IPY_MODEL_530f7729ef174321868689c813cbab16",
              "IPY_MODEL_6ceb216821134bffaacd542be9332afd"
            ],
            "layout": "IPY_MODEL_b4f510c9bb9144ccb2fb6381ad2959b1"
          }
        },
        "3a96896a8b1746b08d855322fc274a7c": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "DescriptionStyleModel",
          "state": {
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "DescriptionStyleModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "StyleView",
            "description_width": ""
          }
        },
        "4111b8dea92d4c73a0d797c900d1c4e4": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "HTMLModel",
          "state": {
            "_dom_classes": [],
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "HTMLModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/controls",
            "_view_module_version": "1.5.0",
            "_view_name": "HTMLView",
            "description": "",
            "description_tooltip": null,
            "layout": "IPY_MODEL_e78c6667146541fdb695db5690fa4301",
            "placeholder": "​",
            "style": "IPY_MODEL_17b7154badac4cae83ae11e0bbc8f881",
            "value": " 18107/18107 [00:00&lt;00:00, 661449.10it/s]"
          }
        },
        "512ed7c39b0a49ed97c4ed9aa9cb47e9": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "ProgressStyleModel",
          "state": {
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "ProgressStyleModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "StyleView",
            "bar_color": null,
            "description_width": ""
          }
        },
        "530f7729ef174321868689c813cbab16": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "FloatProgressModel",
          "state": {
            "_dom_classes": [],
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "FloatProgressModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/controls",
            "_view_module_version": "1.5.0",
            "_view_name": "ProgressView",
            "bar_style": "success",
            "description": "",
            "description_tooltip": null,
            "layout": "IPY_MODEL_da3d1cec9148455ea084b22d7209805e",
            "max": 1,
            "min": 0,
            "orientation": "horizontal",
            "style": "IPY_MODEL_512ed7c39b0a49ed97c4ed9aa9cb47e9",
            "value": 1
          }
        },
        "56b020a70cd34c1c9673d7ebdba23c43": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "DescriptionStyleModel",
          "state": {
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "DescriptionStyleModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "StyleView",
            "description_width": ""
          }
        },
        "5b30c15446eb4a6cbc62498fb6753323": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "DescriptionStyleModel",
          "state": {
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "DescriptionStyleModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "StyleView",
            "description_width": ""
          }
        },
        "6ada793910ae47b0953f6be510d7d935": {
          "model_module": "@jupyter-widgets/base",
          "model_module_version": "1.2.0",
          "model_name": "LayoutModel",
          "state": {
            "_model_module": "@jupyter-widgets/base",
            "_model_module_version": "1.2.0",
            "_model_name": "LayoutModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "LayoutView",
            "align_content": null,
            "align_items": null,
            "align_self": null,
            "border": null,
            "bottom": null,
            "display": null,
            "flex": null,
            "flex_flow": null,
            "grid_area": null,
            "grid_auto_columns": null,
            "grid_auto_flow": null,
            "grid_auto_rows": null,
            "grid_column": null,
            "grid_gap": null,
            "grid_row": null,
            "grid_template_areas": null,
            "grid_template_columns": null,
            "grid_template_rows": null,
            "height": null,
            "justify_content": null,
            "justify_items": null,
            "left": null,
            "margin": null,
            "max_height": null,
            "max_width": null,
            "min_height": null,
            "min_width": null,
            "object_fit": null,
            "object_position": null,
            "order": null,
            "overflow": null,
            "overflow_x": null,
            "overflow_y": null,
            "padding": null,
            "right": null,
            "top": null,
            "visibility": null,
            "width": null
          }
        },
        "6ceb216821134bffaacd542be9332afd": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "HTMLModel",
          "state": {
            "_dom_classes": [],
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "HTMLModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/controls",
            "_view_module_version": "1.5.0",
            "_view_name": "HTMLView",
            "description": "",
            "description_tooltip": null,
            "layout": "IPY_MODEL_6ada793910ae47b0953f6be510d7d935",
            "placeholder": "​",
            "style": "IPY_MODEL_7045995d4587482c8d87797846e13ad9",
            "value": " 966/? [00:16&lt;00:00, 56.13it/s]"
          }
        },
        "7045995d4587482c8d87797846e13ad9": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "DescriptionStyleModel",
          "state": {
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "DescriptionStyleModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "StyleView",
            "description_width": ""
          }
        },
        "79a55387adba484e9485779a07bcc8e9": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "ProgressStyleModel",
          "state": {
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "ProgressStyleModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "StyleView",
            "bar_color": null,
            "description_width": ""
          }
        },
        "79e7a2f67e704862b46c4479a28aa57e": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "HTMLModel",
          "state": {
            "_dom_classes": [],
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "HTMLModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/controls",
            "_view_module_version": "1.5.0",
            "_view_name": "HTMLView",
            "description": "",
            "description_tooltip": null,
            "layout": "IPY_MODEL_260f33f2bfc745cf904790692b45daa3",
            "placeholder": "​",
            "style": "IPY_MODEL_3a96896a8b1746b08d855322fc274a7c",
            "value": ""
          }
        },
        "7d1e98340eb54ca7be701aba5cf76943": {
          "model_module": "@jupyter-widgets/base",
          "model_module_version": "1.2.0",
          "model_name": "LayoutModel",
          "state": {
            "_model_module": "@jupyter-widgets/base",
            "_model_module_version": "1.2.0",
            "_model_name": "LayoutModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "LayoutView",
            "align_content": null,
            "align_items": null,
            "align_self": null,
            "border": null,
            "bottom": null,
            "display": null,
            "flex": null,
            "flex_flow": null,
            "grid_area": null,
            "grid_auto_columns": null,
            "grid_auto_flow": null,
            "grid_auto_rows": null,
            "grid_column": null,
            "grid_gap": null,
            "grid_row": null,
            "grid_template_areas": null,
            "grid_template_columns": null,
            "grid_template_rows": null,
            "height": null,
            "justify_content": null,
            "justify_items": null,
            "left": null,
            "margin": null,
            "max_height": null,
            "max_width": null,
            "min_height": null,
            "min_width": null,
            "object_fit": null,
            "object_position": null,
            "order": null,
            "overflow": null,
            "overflow_x": null,
            "overflow_y": null,
            "padding": null,
            "right": null,
            "top": null,
            "visibility": null,
            "width": null
          }
        },
        "7fff264309184763be76c74febde5af1": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "HBoxModel",
          "state": {
            "_dom_classes": [],
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "HBoxModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/controls",
            "_view_module_version": "1.5.0",
            "_view_name": "HBoxView",
            "box_style": "",
            "children": [
              "IPY_MODEL_a51848bc90674b5bbfe6aa10b1fbd92b",
              "IPY_MODEL_f713cc5ab93e467699537e1033853259",
              "IPY_MODEL_880ed6db148b41fe93ccf987173c95b0"
            ],
            "layout": "IPY_MODEL_b0af4291ebd44162bc27b36c1ad3f651"
          }
        },
        "8271841f536f476fa7f168285169b8b0": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "HBoxModel",
          "state": {
            "_dom_classes": [],
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "HBoxModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/controls",
            "_view_module_version": "1.5.0",
            "_view_name": "HBoxView",
            "box_style": "",
            "children": [
              "IPY_MODEL_d04403d6d9de45229ab199c84d8e78b1",
              "IPY_MODEL_83516e53d8044b5984c31b0cfa983454",
              "IPY_MODEL_4111b8dea92d4c73a0d797c900d1c4e4"
            ],
            "layout": "IPY_MODEL_110a1f620812433692b0442ba588013c"
          }
        },
        "83516e53d8044b5984c31b0cfa983454": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "FloatProgressModel",
          "state": {
            "_dom_classes": [],
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "FloatProgressModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/controls",
            "_view_module_version": "1.5.0",
            "_view_name": "ProgressView",
            "bar_style": "success",
            "description": "",
            "description_tooltip": null,
            "layout": "IPY_MODEL_114607d303c64d558617e41975b25270",
            "max": 18107,
            "min": 0,
            "orientation": "horizontal",
            "style": "IPY_MODEL_9aca93d3cde5487c8d83e9007673f227",
            "value": 18107
          }
        },
        "880ed6db148b41fe93ccf987173c95b0": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "HTMLModel",
          "state": {
            "_dom_classes": [],
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "HTMLModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/controls",
            "_view_module_version": "1.5.0",
            "_view_name": "HTMLView",
            "description": "",
            "description_tooltip": null,
            "layout": "IPY_MODEL_928f41cfb6184310afb07d861c17a413",
            "placeholder": "​",
            "style": "IPY_MODEL_91c3e9b25c94440181ce6e679ef357c3",
            "value": " 17160/17160 [22:53&lt;00:00, 12.60it/s, epoch=39, loss=2.22, val_loss=3.3]"
          }
        },
        "8af2647d8486443a8a025bc30e9ddac6": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "HTMLModel",
          "state": {
            "_dom_classes": [],
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "HTMLModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/controls",
            "_view_module_version": "1.5.0",
            "_view_name": "HTMLView",
            "description": "",
            "description_tooltip": null,
            "layout": "IPY_MODEL_d939b58e958641bdb4f2a2accc1c3645",
            "placeholder": "​",
            "style": "IPY_MODEL_5b30c15446eb4a6cbc62498fb6753323",
            "value": " 12%"
          }
        },
        "91c3e9b25c94440181ce6e679ef357c3": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "DescriptionStyleModel",
          "state": {
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "DescriptionStyleModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "StyleView",
            "description_width": ""
          }
        },
        "928f41cfb6184310afb07d861c17a413": {
          "model_module": "@jupyter-widgets/base",
          "model_module_version": "1.2.0",
          "model_name": "LayoutModel",
          "state": {
            "_model_module": "@jupyter-widgets/base",
            "_model_module_version": "1.2.0",
            "_model_name": "LayoutModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "LayoutView",
            "align_content": null,
            "align_items": null,
            "align_self": null,
            "border": null,
            "bottom": null,
            "display": null,
            "flex": null,
            "flex_flow": null,
            "grid_area": null,
            "grid_auto_columns": null,
            "grid_auto_flow": null,
            "grid_auto_rows": null,
            "grid_column": null,
            "grid_gap": null,
            "grid_row": null,
            "grid_template_areas": null,
            "grid_template_columns": null,
            "grid_template_rows": null,
            "height": null,
            "justify_content": null,
            "justify_items": null,
            "left": null,
            "margin": null,
            "max_height": null,
            "max_width": null,
            "min_height": null,
            "min_width": null,
            "object_fit": null,
            "object_position": null,
            "order": null,
            "overflow": null,
            "overflow_x": null,
            "overflow_y": null,
            "padding": null,
            "right": null,
            "top": null,
            "visibility": null,
            "width": null
          }
        },
        "9aca93d3cde5487c8d83e9007673f227": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "ProgressStyleModel",
          "state": {
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "ProgressStyleModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "StyleView",
            "bar_color": null,
            "description_width": ""
          }
        },
        "a51848bc90674b5bbfe6aa10b1fbd92b": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "HTMLModel",
          "state": {
            "_dom_classes": [],
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "HTMLModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/controls",
            "_view_module_version": "1.5.0",
            "_view_name": "HTMLView",
            "description": "",
            "description_tooltip": null,
            "layout": "IPY_MODEL_eac3d467f0e24fc5a461c4f5037d76da",
            "placeholder": "​",
            "style": "IPY_MODEL_56b020a70cd34c1c9673d7ebdba23c43",
            "value": "100%"
          }
        },
        "a81f6c3bb6a4482b86d028d608b04559": {
          "model_module": "@jupyter-widgets/base",
          "model_module_version": "1.2.0",
          "model_name": "LayoutModel",
          "state": {
            "_model_module": "@jupyter-widgets/base",
            "_model_module_version": "1.2.0",
            "_model_name": "LayoutModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "LayoutView",
            "align_content": null,
            "align_items": null,
            "align_self": null,
            "border": null,
            "bottom": null,
            "display": null,
            "flex": null,
            "flex_flow": null,
            "grid_area": null,
            "grid_auto_columns": null,
            "grid_auto_flow": null,
            "grid_auto_rows": null,
            "grid_column": null,
            "grid_gap": null,
            "grid_row": null,
            "grid_template_areas": null,
            "grid_template_columns": null,
            "grid_template_rows": null,
            "height": null,
            "justify_content": null,
            "justify_items": null,
            "left": null,
            "margin": null,
            "max_height": null,
            "max_width": null,
            "min_height": null,
            "min_width": null,
            "object_fit": null,
            "object_position": null,
            "order": null,
            "overflow": null,
            "overflow_x": null,
            "overflow_y": null,
            "padding": null,
            "right": null,
            "top": null,
            "visibility": null,
            "width": null
          }
        },
        "b0af4291ebd44162bc27b36c1ad3f651": {
          "model_module": "@jupyter-widgets/base",
          "model_module_version": "1.2.0",
          "model_name": "LayoutModel",
          "state": {
            "_model_module": "@jupyter-widgets/base",
            "_model_module_version": "1.2.0",
            "_model_name": "LayoutModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "LayoutView",
            "align_content": null,
            "align_items": null,
            "align_self": null,
            "border": null,
            "bottom": null,
            "display": null,
            "flex": null,
            "flex_flow": null,
            "grid_area": null,
            "grid_auto_columns": null,
            "grid_auto_flow": null,
            "grid_auto_rows": null,
            "grid_column": null,
            "grid_gap": null,
            "grid_row": null,
            "grid_template_areas": null,
            "grid_template_columns": null,
            "grid_template_rows": null,
            "height": null,
            "justify_content": null,
            "justify_items": null,
            "left": null,
            "margin": null,
            "max_height": null,
            "max_width": null,
            "min_height": null,
            "min_width": null,
            "object_fit": null,
            "object_position": null,
            "order": null,
            "overflow": null,
            "overflow_x": null,
            "overflow_y": null,
            "padding": null,
            "right": null,
            "top": null,
            "visibility": null,
            "width": null
          }
        },
        "b4f510c9bb9144ccb2fb6381ad2959b1": {
          "model_module": "@jupyter-widgets/base",
          "model_module_version": "1.2.0",
          "model_name": "LayoutModel",
          "state": {
            "_model_module": "@jupyter-widgets/base",
            "_model_module_version": "1.2.0",
            "_model_name": "LayoutModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "LayoutView",
            "align_content": null,
            "align_items": null,
            "align_self": null,
            "border": null,
            "bottom": null,
            "display": null,
            "flex": null,
            "flex_flow": null,
            "grid_area": null,
            "grid_auto_columns": null,
            "grid_auto_flow": null,
            "grid_auto_rows": null,
            "grid_column": null,
            "grid_gap": null,
            "grid_row": null,
            "grid_template_areas": null,
            "grid_template_columns": null,
            "grid_template_rows": null,
            "height": null,
            "justify_content": null,
            "justify_items": null,
            "left": null,
            "margin": null,
            "max_height": null,
            "max_width": null,
            "min_height": null,
            "min_width": null,
            "object_fit": null,
            "object_position": null,
            "order": null,
            "overflow": null,
            "overflow_x": null,
            "overflow_y": null,
            "padding": null,
            "right": null,
            "top": null,
            "visibility": null,
            "width": null
          }
        },
        "d04403d6d9de45229ab199c84d8e78b1": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "HTMLModel",
          "state": {
            "_dom_classes": [],
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "HTMLModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/controls",
            "_view_module_version": "1.5.0",
            "_view_name": "HTMLView",
            "description": "",
            "description_tooltip": null,
            "layout": "IPY_MODEL_a81f6c3bb6a4482b86d028d608b04559",
            "placeholder": "​",
            "style": "IPY_MODEL_32ab830293104d33b6f584b0ed030aeb",
            "value": "100%"
          }
        },
        "d3ac645daf904649988e69aa58fb665a": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "ProgressStyleModel",
          "state": {
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "ProgressStyleModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "StyleView",
            "bar_color": null,
            "description_width": ""
          }
        },
        "d939b58e958641bdb4f2a2accc1c3645": {
          "model_module": "@jupyter-widgets/base",
          "model_module_version": "1.2.0",
          "model_name": "LayoutModel",
          "state": {
            "_model_module": "@jupyter-widgets/base",
            "_model_module_version": "1.2.0",
            "_model_name": "LayoutModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "LayoutView",
            "align_content": null,
            "align_items": null,
            "align_self": null,
            "border": null,
            "bottom": null,
            "display": null,
            "flex": null,
            "flex_flow": null,
            "grid_area": null,
            "grid_auto_columns": null,
            "grid_auto_flow": null,
            "grid_auto_rows": null,
            "grid_column": null,
            "grid_gap": null,
            "grid_row": null,
            "grid_template_areas": null,
            "grid_template_columns": null,
            "grid_template_rows": null,
            "height": null,
            "justify_content": null,
            "justify_items": null,
            "left": null,
            "margin": null,
            "max_height": null,
            "max_width": null,
            "min_height": null,
            "min_width": null,
            "object_fit": null,
            "object_position": null,
            "order": null,
            "overflow": null,
            "overflow_x": null,
            "overflow_y": null,
            "padding": null,
            "right": null,
            "top": null,
            "visibility": null,
            "width": null
          }
        },
        "da3d1cec9148455ea084b22d7209805e": {
          "model_module": "@jupyter-widgets/base",
          "model_module_version": "1.2.0",
          "model_name": "LayoutModel",
          "state": {
            "_model_module": "@jupyter-widgets/base",
            "_model_module_version": "1.2.0",
            "_model_name": "LayoutModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "LayoutView",
            "align_content": null,
            "align_items": null,
            "align_self": null,
            "border": null,
            "bottom": null,
            "display": null,
            "flex": null,
            "flex_flow": null,
            "grid_area": null,
            "grid_auto_columns": null,
            "grid_auto_flow": null,
            "grid_auto_rows": null,
            "grid_column": null,
            "grid_gap": null,
            "grid_row": null,
            "grid_template_areas": null,
            "grid_template_columns": null,
            "grid_template_rows": null,
            "height": null,
            "justify_content": null,
            "justify_items": null,
            "left": null,
            "margin": null,
            "max_height": null,
            "max_width": null,
            "min_height": null,
            "min_width": null,
            "object_fit": null,
            "object_position": null,
            "order": null,
            "overflow": null,
            "overflow_x": null,
            "overflow_y": null,
            "padding": null,
            "right": null,
            "top": null,
            "visibility": null,
            "width": "20px"
          }
        },
        "e78c6667146541fdb695db5690fa4301": {
          "model_module": "@jupyter-widgets/base",
          "model_module_version": "1.2.0",
          "model_name": "LayoutModel",
          "state": {
            "_model_module": "@jupyter-widgets/base",
            "_model_module_version": "1.2.0",
            "_model_name": "LayoutModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "LayoutView",
            "align_content": null,
            "align_items": null,
            "align_self": null,
            "border": null,
            "bottom": null,
            "display": null,
            "flex": null,
            "flex_flow": null,
            "grid_area": null,
            "grid_auto_columns": null,
            "grid_auto_flow": null,
            "grid_auto_rows": null,
            "grid_column": null,
            "grid_gap": null,
            "grid_row": null,
            "grid_template_areas": null,
            "grid_template_columns": null,
            "grid_template_rows": null,
            "height": null,
            "justify_content": null,
            "justify_items": null,
            "left": null,
            "margin": null,
            "max_height": null,
            "max_width": null,
            "min_height": null,
            "min_width": null,
            "object_fit": null,
            "object_position": null,
            "order": null,
            "overflow": null,
            "overflow_x": null,
            "overflow_y": null,
            "padding": null,
            "right": null,
            "top": null,
            "visibility": null,
            "width": null
          }
        },
        "eac3d467f0e24fc5a461c4f5037d76da": {
          "model_module": "@jupyter-widgets/base",
          "model_module_version": "1.2.0",
          "model_name": "LayoutModel",
          "state": {
            "_model_module": "@jupyter-widgets/base",
            "_model_module_version": "1.2.0",
            "_model_name": "LayoutModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "LayoutView",
            "align_content": null,
            "align_items": null,
            "align_self": null,
            "border": null,
            "bottom": null,
            "display": null,
            "flex": null,
            "flex_flow": null,
            "grid_area": null,
            "grid_auto_columns": null,
            "grid_auto_flow": null,
            "grid_auto_rows": null,
            "grid_column": null,
            "grid_gap": null,
            "grid_row": null,
            "grid_template_areas": null,
            "grid_template_columns": null,
            "grid_template_rows": null,
            "height": null,
            "justify_content": null,
            "justify_items": null,
            "left": null,
            "margin": null,
            "max_height": null,
            "max_width": null,
            "min_height": null,
            "min_width": null,
            "object_fit": null,
            "object_position": null,
            "order": null,
            "overflow": null,
            "overflow_x": null,
            "overflow_y": null,
            "padding": null,
            "right": null,
            "top": null,
            "visibility": null,
            "width": null
          }
        },
        "ec9417d5c4e54d18966e0140e60e4f7e": {
          "model_module": "@jupyter-widgets/base",
          "model_module_version": "1.2.0",
          "model_name": "LayoutModel",
          "state": {
            "_model_module": "@jupyter-widgets/base",
            "_model_module_version": "1.2.0",
            "_model_name": "LayoutModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "LayoutView",
            "align_content": null,
            "align_items": null,
            "align_self": null,
            "border": null,
            "bottom": null,
            "display": null,
            "flex": null,
            "flex_flow": null,
            "grid_area": null,
            "grid_auto_columns": null,
            "grid_auto_flow": null,
            "grid_auto_rows": null,
            "grid_column": null,
            "grid_gap": null,
            "grid_row": null,
            "grid_template_areas": null,
            "grid_template_columns": null,
            "grid_template_rows": null,
            "height": null,
            "justify_content": null,
            "justify_items": null,
            "left": null,
            "margin": null,
            "max_height": null,
            "max_width": null,
            "min_height": null,
            "min_width": null,
            "object_fit": null,
            "object_position": null,
            "order": null,
            "overflow": null,
            "overflow_x": null,
            "overflow_y": null,
            "padding": null,
            "right": null,
            "top": null,
            "visibility": null,
            "width": null
          }
        },
        "f6971c6f2b22427cb2b58ffffda71135": {
          "model_module": "@jupyter-widgets/base",
          "model_module_version": "1.2.0",
          "model_name": "LayoutModel",
          "state": {
            "_model_module": "@jupyter-widgets/base",
            "_model_module_version": "1.2.0",
            "_model_name": "LayoutModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "LayoutView",
            "align_content": null,
            "align_items": null,
            "align_self": null,
            "border": null,
            "bottom": null,
            "display": null,
            "flex": null,
            "flex_flow": null,
            "grid_area": null,
            "grid_auto_columns": null,
            "grid_auto_flow": null,
            "grid_auto_rows": null,
            "grid_column": null,
            "grid_gap": null,
            "grid_row": null,
            "grid_template_areas": null,
            "grid_template_columns": null,
            "grid_template_rows": null,
            "height": null,
            "justify_content": null,
            "justify_items": null,
            "left": null,
            "margin": null,
            "max_height": null,
            "max_width": null,
            "min_height": null,
            "min_width": null,
            "object_fit": null,
            "object_position": null,
            "order": null,
            "overflow": null,
            "overflow_x": null,
            "overflow_y": null,
            "padding": null,
            "right": null,
            "top": null,
            "visibility": null,
            "width": null
          }
        },
        "f713cc5ab93e467699537e1033853259": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "FloatProgressModel",
          "state": {
            "_dom_classes": [],
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "FloatProgressModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/controls",
            "_view_module_version": "1.5.0",
            "_view_name": "ProgressView",
            "bar_style": "success",
            "description": "",
            "description_tooltip": null,
            "layout": "IPY_MODEL_7d1e98340eb54ca7be701aba5cf76943",
            "max": 17160,
            "min": 0,
            "orientation": "horizontal",
            "style": "IPY_MODEL_d3ac645daf904649988e69aa58fb665a",
            "value": 17160
          }
        }
      }
    }
  },
  "nbformat": 4,
  "nbformat_minor": 5
}
